【问题标题】:Correct way to use std::enable_if使用 std::enable_if 的正确方法
【发布时间】:2019-08-11 11:13:02
【问题描述】:

这些类之间有什么区别?正是这些方法与 enable_if。

/// Alias of std::enable_if...
template <bool B, typename T = void>
using Enable_if = typename std::enable_if<B, T>::type;

Template<typename T, std::size_t N>
class A {
   ...
    template <std::size_t NN = N,
          typename = Enable_if<NN == 2>>
    Some_Return_Type
    method(param1, param2)
    {}

    template <std::size_t NN = N,
              typename = Enable_if<NN == 1>>
    Some_Return_Type
    method(param1)
    {}


};


Template<typename T, std::size_t N>
class B {
   ...
    Enable_if<N == 2, Some_Return_Type>
    method(param1, param2)
    {}

    Enable_if<N == 1, Some_Return_Type>
    method(param1)
    {}
};

在我有的情况下使用 enable_if 的正确方法是什么:

  • 至少有 2 个方法仅在参数上有所不同,并且它们具有相同的名称,但其中只有一个必须是“活动的”(如果 N == 1 其中一个,如果 N == 2 另一个)。
  • 只有一种方法在 N == 0 时有效,而在其他情况下无效。

我想得到类似的东西:

Obj<int, 2> obj2;
Obj<int, 0> obj0;
Obj<int, 1> obj1;

如果我在 IDE obj0. 中编写它只显示 N == 0 的方法; obj1. 仅限 N == 1, ... .

谢谢。

【问题讨论】:

  • 您希望哪种方法可用于 N==0?
  • 作为说明,C++14添加了库类型别名std::enable_if_t&lt;bool, typename&gt;,相当于你的Enable_if

标签: c++ c++11


【解决方案1】:

请注意,enable_if 旨在触发 SFINAE:如果模板参数替换在其 立即 上下文中失败,则不是编译错误。

这正是class A 中发生的情况:当用户调用a.method(...) 时,编译器尝试实例化成员函数模板method,将NN 参数替换为常量,这可能会失败。

但是,在 B::method 的情况下,当编译器替换 N 时,在类模板 B 实例化期间会发生“错误”替换。故障发生在远离参数的直接上下文的地方,在本例中为template&lt;typename T, std::size_t N&gt; class B

这就是为什么在第二种情况下你会得到一个编译错误,而不是 SFINAE。

因此,要根据 类模板 参数启用/禁用成员函数,请使用第一种方法,根据需要组合条件。例如:

template <typename T, std::size_t N>
class A {
    template <std::size_t NN = N, typename = std::enable_if_t<NN == 2 || NN == 0>>
    void method(int, int)
    {}

    template <std::size_t NN = N, typename = std::enable_if_t<NN == 1 || NN == 0>>
    void method(int)
    {}
};

更新: enable_if 的工作原理。大致可以这样实现:

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

template<class T>
struct enable_if<true, T> {
    using type = T;
};

请注意,如果第一个参数是 falseenable_if 没有内部 type,所以 enable_if&lt;false, int&gt;::type 格式不正确。这就是触发 SFINAE 的原因。

【讨论】:

  • A 类是实现 SFINAE 的正确方法,好的,但我看不懂第二部分。在 A 类中,如果 NN == 2(或 NN == 1Enable_if 将 void 返回到第二个类型名,因此该方法是“已定义”的,我可以调用它。替换失败时返回什么?它如何禁用该方法?而且我不明白为什么我在 B 类中出现错误。谢谢和抱歉:(
  • @Sam 查看我关于enable_if 机制的更新。至于您的第二个问题,我试图回答:B 中出现错误,因为它不是 SFINAE:仅当在immediate context 中失败时,替换失败才不是错误,B 不是这种情况.
  • B@Sam 失败的原因是它取决于 何时 评估 enable_if。基本上,SFINAE 通俗地说就是“如果我们不能建造它,就把它扔掉,然后找一个我们可以建造的。”在A中,调用method()会失败,因为它依赖于method()的模板参数;这意味着编译器将检查每个提供的method() 版本,以寻找一个有效的版本。对于B,它依赖于B 的模板参数,因此编译器会检查每个提供的B 版本是否有效。但是只有一个 B,所以找不到。
  • (这又是因为模板被实例化的时候。例如,当你创建一个A&lt;int, 2&gt;时,编译器将通过在任何地方填写A的模板参数来构建它在这种情况下,这意味着填写method()的第一个模板参数的默认值......但method()本身仍然是一个模板,因此在它本身被实例化或专门化之前无法编译(例如如果您调用A&lt;int, 2&gt;::method(),或定义A&lt;int, 2&gt;::method&lt;1&gt;() 的显式特化)。由于在您使用method() 之前信息不可用,因此SFINAE 运行method
猜你喜欢
  • 2021-11-10
  • 1970-01-01
  • 2014-08-29
  • 1970-01-01
  • 2017-12-11
  • 2018-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多