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 **) {});
}