将lambda转换为std :: function时强制执行const正确性

Zee*_*bit 4 c++ lambda const

我有一个函数,它接受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)

如何强制执行此操作并仍然保留模板参数?

sky*_*ack 5

需要注意的是std::add_const_t<int &>就是int &,因为你不添加constint.相反,您要添加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)