【问题标题】:enable_if to Add a function parameter that has a default argument?enable_if 添加具有默认参数的函数参数?
【发布时间】:2015-03-13 19:04:36
【问题描述】:

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

•场景 2:添加具有默认参数的函数参数:

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

场景 2 未命名参数。你可以说::type Dummy = BAR,但是名称​​Dummy 是无关紧要的,给它一个名称可能会触发一个未引用参数 警告。您必须选择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;
 }

【问题讨论】:

  • 例如,在 (ab) 使用重载解析时很有用。
  • 无法访问omull 部分。
  • enable_if 启用函数,而不是参数。

标签: c++ sfinae enable-if


【解决方案1】:

微软的文档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 参数用于确定将实例化加倍重载 如果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 函数模板参数应用于您在 帖子,你会写这样的:

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

【讨论】:

  • 谢谢!我终于找到了关于将enable_if 用于 SFINAE 的明确解释。你的回答让我学到了很多!一直到std::enable_if_t&lt;some_condition&gt; * = nullptr 的缩写真的很有帮助!我想问一下,为什么要把void **缩写成std::enable_if&lt;some_condition&gt;::type *,我认为后者实际上是void *?高级欣赏它。
【解决方案2】:

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 &lt;type_traits&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-16
    • 2021-11-25
    • 2012-01-11
    • 2017-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多