2015-03-13 130 views
5

我无法理解第二个场景here。它说:enable_if添加一个具有默认参数的函数参数?

•方案2:添加具有默认参数的函数参数:

template <your_stuff> your_return_type_if_present 
yourfunction(args, enable_if_t<your condition, FOO> = BAR) { 
    // ... 
} 

方案2离开参数命名。您可以说::type Dummy = BAR,但名称虚拟是无关紧要的,并且给它起一个名字很可能会触发未引用的参数警告。您必须选择FOO函数参数类型和BAR默认参数。你可以说int0,但然后你的代码的用户可能会意外地传递给函数一个额外的整数,将被忽略。相反,我们建议您使用void **,要么0nullptr因为几乎没有什么可转换为void **

template <your_stuff> your_return_type_if_present 
yourfunction(args, typename enable_if<your_condition, void **>::type=nullptr) { 
// ... 
} 

如果方案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; 
} 
+0

使用重载例如当(AB),它可以是有用的。 – BartoszKP 2015-03-13 19:08:56

+0

无法到达'omull'部分。 – Jarod42 2015-03-13 19:22:04

+0

enable_if启用该功能,而不是参数。 – 2015-03-13 19:39:23

回答

3

enable_if实例(如果它帮助):

对于使用非void返回类型的功能:

对于单条件:

template <template T, typename std::enable_if<!std::is_same<T,std::string>::value>::type* = nullptr > 
T func(T x){} 

对于多个条件:

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


对于void返回类型的功能:

对于单条件:

template <template T> 
typename std::enable_if<!std::is_same<T,std::string>::value>::type 
func(T x){} 

对于多个条件:

template <template T> 
typename std::enable_if<!std::is_same<T,std::string>::value &&!std::is_same<T,int>::value>::type 
func(T x){} 

不要忘了包括#include <type_traits>

6

微软的文档there 存在都不清晰。改为使用this

提供了一个函数模板与形式的一位不愿透露姓名的默认参数:

typename enable_if<your_condition, void **>::type = nullptr 

(如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; 
} 

输出是:

Doubling 2 gives 4 
4 
Squaring 3.3 gives 10.89 
10.89 

在功能模板foo这两种过载,第一个加倍它是 类型T参数,第二个正方形它的参数,并且使用SFINAE 参数来确定如果T是,则将实例化加倍过载,否则将选择平方过载。

Tint,条件:

!std::is_same<T,int>::value 

控制所述平方过载的SFINAE参数为假。因此 类型说明符:

typename std::enable_if<!std::is_same<T,int>::value, void **>::type = nullptr 

无法编译。这是模板解析中的替代失败。将 int替换为T中的平方过载为不可行。所以平方过载从运行中消除了 ,并且只剩下加倍过载来实例化函数调用 。

T是(说)double,而不是int,则刚好相反发生 ,只有平方超载生存模板的分辨率。拨打电话foo(2) ,你会倍增。拨打电话foo(3.3)即可。

MS的标本SFINAE参数在这里是不必要的冗长。

template< bool B, class T = void > 
struct enable_if; 

按C++ 11标准和更高版本,默认Tvoid。所以类似的:

typename std::enable_if<some_condition, void **>::type = nullptr 

能以及简写为:

typename std::enable_if<some_condition>::type * = nullptr 

,并作为C++ 14的标准有:

template< bool B, class T = void > 
using enable_if_t = typename enable_if<B,T>::type 

因此同样SFINAE参数进一步缩短为:

std::enable_if_t<some_condition> * = nullptr 

应用一个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 
+0

谢谢!我终于找到了关于在SFINAE中使用'enable_if'的明确解释。你的回答让我学到很多东西!一直到'std :: enable_if_t * = nullptr'的缩写真的很有帮助!我想问为什么把'void **'缩写为'std :: enable_if :: type *',后者我认为其实是'void *'?欣赏它先进。 – astroboylrx 2016-04-26 06:49:42