Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/163.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 将lambdas转换为std::function时强制执行常量正确性_C++_Lambda_Constants - Fatal编程技术网

C++ 将lambdas转换为std::function时强制执行常量正确性

C++ 将lambdas转换为std::function时强制执行常量正确性,c++,lambda,constants,C++,Lambda,Constants,我有一个函数,它接受一个std::function作为参数。但是,我希望确保传入的函数不允许修改传递给它的参数 下面是该函数的简单版本(请注意,T可以并且通常是一个参考): 如何在执行此操作的同时仍保留模板参数?在模板的帮助下,可以使用static\u assert使编译失败 //Base case - T is non-const, possibly pointer or reference template <typename T> struct is_const_param {

我有一个函数,它接受一个
std::function
作为参数。但是,我希望确保传入的函数不允许修改传递给它的参数

下面是该函数的简单版本(请注意,
T
可以并且通常是一个参考):


如何在执行此操作的同时仍保留模板参数?

在模板的帮助下,可以使用
static\u assert
使编译失败

//Base case - T is non-const, possibly pointer or reference
template <typename T> struct is_const_param { static constexpr bool value = !std::is_lvalue_reference<T>::value && !std::is_rvalue_reference<T>::value && !std::is_pointer<T>::value; };

//T is const, but possibly pointer to non-const
template <typename T> struct is_const_param<const T> { static constexpr bool value = !std::is_pointer<T>::value; };

//Remove reference, try again
template <typename T> struct is_const_param<const T&> : is_const_param<const T> {  };

//Remove reference, try again
template <typename T> struct is_const_param<const T&&> : is_const_param<const T> {  };

//Remove pointer, try again
template <typename T> struct is_const_param<const T*> : is_const_param<const T> { };

//Remove pointer, try again
template <typename T> struct is_const_param<const T* const> : is_const_param<const T> { };
此设置仅在
T
为以下情况时成功:

  • 按值传递(见下文)
  • 通过常量引用传递
  • 由指针传递到常量
  • 如果您想查看使其成功或失败的示例,可以查看一些测试用例



    这被设置为允许正常地通过值传递,如
    Bar
    。如果要将其更改为仅允许
    ,请删除
    is_const_参数
    专门化,并将非专门化模板中的
    的初始化更改为
    。您可以看到。

    注意,
    std::add_const_t
    int&
    ,因为您没有将
    const
    添加到
    int
    。相反,您将
    const
    添加到对
    int
    的引用中,并获得对
    int
    的常量引用(即
    int&
    ),而不是对
    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&) {});
    }
    
    #包括
    #包括
    模板
    使用type=std::add_const_t;}将结构转换为_const_{;
    模板
    使用type=std::add_const_t&}将结构转换为_const_{;
    模板
    使用to_const_t=typename to_const_::type;
    模板
    空栏(标准::函数func)
    {}
    int main(){
    条([](int&){});
    }
    
    除非您将上面的代码转换为:

    Bar<int&>([](const int &) {});
    
    Bar([](常量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>
    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 **) {});
    }
    
    #包括
    #包括
    模板
    使用type=std::add_const_t;}将结构转换为_const_{;
    模板
    使用type=std::add_const_t&}将结构转换为_const_{;
    模板
    使用type=std::add_const_t&&;}将结构添加到_const_{;
    模板
    使用type=std::conditional_t;}将结构转换为_const_{;
    模板
    使用type=std::conditional_t;}将结构转换为_const_{;
    模板
    使用to_const_t=typename to_const_::type;
    模板
    空栏(标准::函数func)
    {}
    int main(){
    Bar([](常量整数**{});
    }
    
    注意
    std::add_const\u t
    int&
    @aschepler,我在文档中也看到了这一点。所以我甚至试着做了一个黑客版本:
    const T
    ,我想这可以推断为
    const int&
    。但是没有。即使我将
    std::add_const\t
    替换为
    const t
    @Zeenobit,它仍然可以编译得很好:模板不是宏的。这更类似于
    typedef int&T;常数ref-再次
    ref
    将是
    int&
    。与指针比较:
    typedefint*T;T const ptr
    得到一个
    int*const
    而不是
    int-const*
    。那么
    T**
    呢?这太完美了。谢谢
    //Base case - T is non-const, possibly pointer or reference
    template <typename T> struct is_const_param { static constexpr bool value = !std::is_lvalue_reference<T>::value && !std::is_rvalue_reference<T>::value && !std::is_pointer<T>::value; };
    
    //T is const, but possibly pointer to non-const
    template <typename T> struct is_const_param<const T> { static constexpr bool value = !std::is_pointer<T>::value; };
    
    //Remove reference, try again
    template <typename T> struct is_const_param<const T&> : is_const_param<const T> {  };
    
    //Remove reference, try again
    template <typename T> struct is_const_param<const T&&> : is_const_param<const T> {  };
    
    //Remove pointer, try again
    template <typename T> struct is_const_param<const T*> : is_const_param<const T> { };
    
    //Remove pointer, try again
    template <typename T> struct is_const_param<const T* const> : is_const_param<const T> { };
    
    template <class T>
    void Bar(std::function<void(T)>)
    {
        static_assert(is_const_param<T>::value, "...");
    }
    
    #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&) {});
    }
    
    Bar<int&>([](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>
    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 **) {});
    }