为白名单类型约束模板函数的更好方法,SFINAE
Better way for constrain template function for white listed types, SFINAE?
我想创建一个特性/接口,例如is_good
,并针对其规范实现我的通用函数。
在一些关于SFINAE的在线资源的帮助下,我想出了以下代码。
template<class C>
struct is_good: std::false_type
{
};
template<>
struct is_good<A<double, 2>>: std::true_type
{
};
template<>
struct is_good<B<double, 2, 3>>: std::true_type
{
};
template<template<class> class C, class T>
using check_constraints = std::enable_if_t<C<T>::value, bool>;
}
我的通用函数定义如下:
template<class T, template<class> class C = is_good,
typename = check_constraints<C, T>>
void compute(const T& t) {}
使用
// works
compute(A<double,2>());
compute(B<double,2, 3>());
// should not compile.
compute(B<double,5, 6>());
然而,这似乎有点麻烦。我必须准备
template<class T, template<class> class C = is_good,
typename = check_constraints<C, T>>
到我计划通用化的所有函数。
有更好的方法吗?
更新
这个问题的基础是,假设我知道我的函数体与类型A
&B
&C
,我如何定义我的函数?
例如,在其他语言中,也许你可以做
using T = Union{A, B, C};
void compute(T t){...}
# works with A
compute(A());
# works with B
compute(B());
无论CCD_ 5看起来如何。
您的问题不清楚。但是,如果is_2d
必须在所有函数中,为什么不将其移动到check_constraints
呢?参考编号:https://gcc.godbolt.org/z/s9Jql-
template<class T>
using check_constraints = std::enable_if_t<is_2d<T>::value, bool>;
template<class T, typename = check_constraints<T>>
void compute(const T& t){
works(t);
}
更新
如果你只想要一个允许的类型列表,下面的更好,因为你有c++17。https://gcc.godbolt.org/z/kJN7hu
#include<type_traits>
template<class... Types>
struct TypeContainer{
template<class T>
using contains = typename std::disjunction< std::is_same<T,Types>... >::type;
};
using allowed_types = TypeContainer<
int,
float
>;
template<class T, typename = std::enable_if_t<allowed_types::contains<T>::value>>
void compute(const T& t);
void foo() {
int i;
compute(i);
//char c; compute(c);
}
然而,这似乎有点麻烦。我必须准备
template<class T, template<class> class C = is_good, typename = check_constraints<C, T>>
到我计划通用化的所有函数。
有更好的方法吗?
我认为C风格的宏是邪恶的,但对于这样的问题,我认为用于该模板签名的宏是合理的。
不管怎样,我建议局部改进一下。
使用您的实际函数样式,在默认模板模板参数(C
)之前使用可推导类型(T
)
template<class T, template<class> class C = is_good,
typename = check_constraints<C, T>>
void compute(const T& t) {}
如果要显式显示不同于默认模板参数(is_good
)的模板模板参数,则必须显式显示可推导类型和模板模板参数
compute<B<double, 2, 3>, is_good_i_hope>(B<double, 2, 3>);
失去了从函数自变量中推导CCD_ 12。
但是,如果您在可推导类型之前表达模板模板参数
template <template<typename> class C = is_good, typename T,
typename = check_constraints<C, T>>
void compute (T const &)
{ }
当您想要显式一个不同于默认的模板模板参数时,您只能显式C
compute<is_good_i_hope>(B<double, 2, 3>);
维持CCD_ 14的推导。
一旦你有了自己的特征,你可以简单地使用SFINAE:
template<class T>
std::enable_if_t<is_good<T>>
compute(const T& t) {}
或
template<class T, std::enable_if_t<is_good<T>, int> = 0>
void compute(const T& t) {}
- 初始化具有非默认构造函数的std::数组项的更好方法
- 有没有比在库中添加一个并非由所有派生类实现的新虚拟函数更好的设计实践
- 对于等待以 std::future wait() 返回的函数的 CPU 使用率或检查标志在循环中休眠一段时间哪个更好?
- 在类的第一个/最后一个实例存在之前/之后调用一对函数.有没有更好的方法?
- 使用构造函数初始化结构还是在之后设置其值更好?
- 对于可移动类型,按值传递比重载函数更好吗?
- 函数的返回是 LPVOID 或更好的指向列表的指针
- 重新定义要在函数中使用的静态变量 - 有没有更好的方法?
- 除了使用 clock() 函数之外,有没有更好的方法来以给定的频率生成/发布数据
- 在构造函数中组织初始值设定项列表的更好方法
- 使用成员函数更改对象或返回并分配它是否被认为是更好的做法?
- 需要一种更好的方法来编写电源函数
- 哪种 c++ 构造函数样式更好
- 有没有更好的方法可以从静态和非静态函数返回相同的字符串文本
- Curly Braces构造函数更喜欢initializer_list而不是更好的匹配.为什么
- 哪一个更好?使用C 代码中的System()函数或使用源代码
- 这是检查 const 函数(如果是否创建某些内容)的更好方法
- 为白名单类型约束模板函数的更好方法,SFINAE
- 调用包含所有所需代码的函数或内部包含所需代码的其他函数的函数更好?
- 是将基类强制转换为派生类更好,还是在基类上创建一个虚拟函数更好