我有一个函数,它接受std::function
一个参数.但是,我想确保传入的函数不允许修改传递给它的参数.
这是函数的简单版本(注意T
可以,通常是参考):
template <class T>
void Bar(std::function<void(std::add_const_t<T>)> func)
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
用法不好:
Bar<int&>([](int&) { /* Do nasty stuff! */ }); /* A-OK! */
Run Code Online (Sandbox Code Playgroud)
我想禁止这种用法,但是这段代码编写得非常好,即使我觉得它不应该.
有趣的是,如果我摆脱模板参数,即:
void Bar(std::function<void(const int&)> func)
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
然后,这种用法不会编译(因为它不应该):
Bar([](int&) { /* Do nasty stuff! */ }); /* Error C2664 */
Run Code Online (Sandbox Code Playgroud)
如何强制执行此操作并仍然保留模板参数?
需要注意的是std::add_const_t<int &>
就是int &
,因为你不添加const
到int
.相反,您要添加const
一个引用,int
并获得一个const引用int
(即int &
),而不是对a的引用const int
.
解决它的一种简单方法可以是:
#include<functional>
#include<type_traits>
template<typename T>
struct to_const_ { using type = std::add_const_t<T>; };
template<typename T>
struct to_const_<T &> { using type = std::add_const_t<T> &; };
template<typename T>
using to_const_t = typename to_const_<T>::type;
template <class T>
void Bar(std::function<void(to_const_t<T>)> func)
{}
int main() {
Bar<int&>([](int&) {});
}
Run Code Online (Sandbox Code Playgroud)
上面的代码不会编译(按要求),除非你把它变成:
Bar<int&>([](const int &) {});
Run Code Online (Sandbox Code Playgroud)
请注意,它仅适用于左值引用,但如果您有了这个想法,则添加对右值引用和指针的支持非常简单.
它遵循一个最小的(可能)工作示例:
#include<functional>
#include<type_traits>
template<typename T>
struct to_const_ { using type = std::add_const_t<T>; };
template<typename T>
struct to_const_<T &> { using type = std::add_const_t<T> &; };
template<typename T>
struct to_const_<T &&> { using type = std::add_const_t<T> &&; };
template<typename T>
struct to_const_<T * const> { using type = std::conditional_t<std::is_pointer<T>::value, typename to_const_<T>::type * const, std::add_const_t<typename to_const_<T>::type> * const>; };
template<typename T>
struct to_const_<T *> { using type = std::conditional_t<std::is_pointer<T>::value, typename to_const_<T>::type *, std::add_const_t<typename to_const_<T>::type> *>; };
template<typename T>
using to_const_t = typename to_const_<T>::type;
template <class T>
void Bar(std::function<void(to_const_t<T>)> func)
{}
int main() {
Bar<int **>([](const int **) {});
}
Run Code Online (Sandbox Code Playgroud)