enable_if 添加具有默认参数的函数参数?

enable_if to Add a function parameter that has a default argument?

我无法理解呈现的第二种情况 here。它说:

•Scenario 2: Adding a function parameter that has a default argument:

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

Scenario 2 leaves the parameter unnamed. You could say ::type Dummy = BAR, but the name Dummy is irrelevant, and giving it a name is likely to trigger an unreferenced parameter warning. You have to choose a FOO function parameter type and BAR default argument. You could say int and 0, but then users of your code could accidentally pass to the function an extra integer that would be ignored. Instead, we recommend that you use void ** and either 0 or nullptr because almost nothing is convertible to 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;
 }

enable_if 示例(如果有帮助):

对于具有非空 return 类型的函数:

单一条件:

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 return 类型的函数:

单一条件:

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>

Microsoft 的文档 there 那里清澈如泥。请改用 this

为函数模板提供未命名的默认参数,格式为:

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

(正如 MS 抄写员所建议的),在您希望的情况下很有用 - 并且仅在情况下 - 编写具有不同行为的函数模板的多个重载 由一个或多个模板参数控制。然后,通过 用表达适当条件的条件替换 your_condition 对模板参数的要求,您可以使用 SFINAE 原则 select 您要为其实例化的特定重载 给定模板参数。

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 参数用于确定将实例化倍增重载 如果 Tint,否则将选择平方重载。

Tint时,条件:

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

控制平方重载的 SFINAE 参数是错误的。最后 类型说明符:

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

编译失败。这是模板解析中的替换失败。代入 在平方重载中 Tint 不可行 。所以平方超载是 从运行中剔除,只剩下加倍重载实例化 函数调用。

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 函数模板参数应用于您在 post,你会这样写:

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