Oz *_* Le 6 c++ sfinae enable-if
我无法理解这里介绍的第二种情况.它说:
•场景2:添加具有默认参数的函数参数:
template <your_stuff> your_return_type_if_present
yourfunction(args, enable_if_t<your condition, FOO> = BAR) {
// ...
}
Run Code Online (Sandbox Code Playgroud)
方案2使参数未命名.你可以说
::type Dummy = BAR,但名字Dummy是无关紧要的,并给它一个名字可能会触发一个未引用的参数警告.您必须选择FOO函数参数类型和BAR默认参数.你可以说int和0,但你的代码的用户可能会意外地传递给函数的一个额外的整数,将被忽略.相反,我们建议您使用void **,要么0或nullptr因为几乎没有什么可转换为void **:
template <your_stuff> your_return_type_if_present
yourfunction(args, typename enable_if<your_condition, void **>::type=nullptr) {
// ...
}
Run Code Online (Sandbox Code Playgroud)
如果方案2使参数未命名,那么它可以使用什么?有没有办法让像这样的代码工作enable_if?
enum otype {oadd,omull};
template<otype o>
int add(int num1, std::enable_if<o == oadd, int>::type int= num2)
{
if (o == omull) return num1 * num1;
if (o == oadd ) return num1 + num2;
}
Run Code Online (Sandbox Code Playgroud)
提供具有表单的未命名默认参数的函数模板:
typename enable_if<your_condition, void **>::type = nullptr
Run Code Online (Sandbox Code Playgroud)
(正如MS抄写员所建议的那样)在以下情况下很有用 - 并且只有在大小写的情况下 - 您希望使用由一个或多个模板参数控制的不同行为来编写函数模板的多个重载.然后,通过替换your_condition表达对模板参数的适当要求的条件,您可以登记SFINAE
原则来选择要为给定模板参数实例化的特定重载.
SFINAE参数 - 让我们称它为 - 实例化函数未使用; 它仅用于在函数模板重载决策中激发SFINAE.因此它可以是无名的,因此它必须是默认的:当你调用函数模板时,它不能强迫你提供额外的,无用的参数.
例如:
#include <type_traits>
#include <iostream>
template <typename T>
T foo(T && t,
typename std::enable_if<std::is_same<T,int>::value, void **>::type = nullptr)
{
std::cout << "Doubling " << t << " gives " << (t + t) << std::endl;
return t + t;
}
template <typename T>
T foo(T && t,
typename std::enable_if<!std::is_same<T,int>::value, void **>::type = nullptr)
{
std::cout << "Squaring " << t << " gives " << (t * t) << std::endl;
return t * t;
}
using namespace std;
int main()
{
cout << foo(2) << endl;
cout << foo(3.3) << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是:
Doubling 2 gives 4
4
Squaring 3.3 gives 10.89
10.89
Run Code Online (Sandbox Code Playgroud)
在函数模板的这两个重载中foo,第一个重载它的类型T参数,第二个重叠其参数,并且SFINAE参数用于确定双重过载将被实例化,如果T是,int并且将另外选择平方过载.
当T是int时,条件:
!std::is_same<T,int>::value
Run Code Online (Sandbox Code Playgroud)
控制平方过载的SFINAE参数是错误的.因此类型说明符:
typename std::enable_if<!std::is_same<T,int>::value, void **>::type = nullptr
Run Code Online (Sandbox Code Playgroud)
无法编译.这是模板解析中的替换失败.替换
int为T在平方超载是不可行的.因此,从运行中消除了平方过载,并且仅留下倍增过载来实例化函数调用.
什么时候T(比方说)double而不是int,那么恰好相反的情况发生,只有平方超负荷存在模板分辨率.打电话foo(2)
,你加倍.打电话foo(3.3),你得到平方.
MS的样本SFINAE参数在这里是不必要的冗长.
template< bool B, class T = void >
struct enable_if;
Run Code Online (Sandbox Code Playgroud)
根据C++ 11 Standard及更高版本,默认T为void.所以喜欢:
typename std::enable_if<some_condition, void **>::type = nullptr
Run Code Online (Sandbox Code Playgroud)
也可以缩写为:
typename std::enable_if<some_condition>::type * = nullptr
Run Code Online (Sandbox Code Playgroud)
从C++ 14开始,该标准具有:
template< bool B, class T = void >
using enable_if_t = typename enable_if<B,T>::type
Run Code Online (Sandbox Code Playgroud)
因此,相同的SFINAE参数可以进一步缩短为:
std::enable_if_t<some_condition> * = nullptr
Run Code Online (Sandbox Code Playgroud)
将SFINAE函数模板参数应用于您在帖子中打手势的案例,您可以这样写:
enum ops {
add,
multiply
};
template<ops Op>
int op(int const & lhs, int const & rhs,
std::enable_if_t<Op == add> * = nullptr)
{
return lhs + rhs;
}
template<ops Op>
int op(int const & lhs, int const & rhs,
std::enable_if_t<Op == multiply> * = nullptr)
{
return lhs * rhs;
}
...
auto i = op<add>(2,3);
auto j = op<multiply>(2,3);
...
// C++14
Run Code Online (Sandbox Code Playgroud)
enable_if示例(如果有帮助的话):
对于具有非 void 返回类型的函数:
对于单一条件:
template <template T, typename std::enable_if<!std::is_same<T,std::string>::value>::type* = nullptr >
T func(T x){}
Run Code Online (Sandbox Code Playgroud)
对于多个条件:
template <template T, typename std::enable_if<!std::is_same<T,std::string>::value &&!std::is_same<T,int>::value>::type* = nullptr >
T func(T x){}
Run Code Online (Sandbox Code Playgroud)
对于单一条件:
template <template T>
typename std::enable_if<!std::is_same<T,std::string>::value>::type
func(T x){}
Run Code Online (Sandbox Code Playgroud)
对于多个条件:
template <template T>
typename std::enable_if<!std::is_same<T,std::string>::value &&!std::is_same<T,int>::value>::type
func(T x){}
Run Code Online (Sandbox Code Playgroud)
不要忘记包括#include <type_traits>