c++ 如何使用std::enable_if禁用成员函数

bqujaahr  于 2023-07-01  发布在  其他
关注(0)|答案(1)|浏览(209)

这些类之间的区别是什么?具体来说,这些成员函数都是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的正确方法是什么:

  • 至少有两个方法,它们的参数不同,并且它们具有相同的名称,但其中一个必须是“活动的”(如果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
  • ...
ojsjcaue

ojsjcaue1#

请注意,enable_if旨在触发SFINAE:如果模板参数替换在其 immediate 上下文中失败,则不是编译错误。
这就是在class A中发生的事情:当用户调用a.method(...)时,编译器尝试示例化成员函数模板method,用常量替换NN参数,这可能会失败。
然而,在B::method的情况下,“坏”替换发生在类模板B示例化期间,当编译器替换N时。失败发生在远离参数的直接上下文的地方,在本例中是template<typename T, std::size_t N> class B
这就是为什么在第二种情况下,你会得到一个编译错误,而不是SFINAE。
因此,要根据 class template 参数启用/禁用成员函数,请使用第一种方法,根据需要组合条件。例如:

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

UPDATE:enable_if的工作原理。大致上,可以这样实现它:

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

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

请注意,如果第一个参数是false,则enable_if没有内部type,因此enable_if<false, int>::type将是病态的。这就是触发SFINAE。

相关问题