当前位置: 首页 > 知识库问答 >
问题:

条件声明成员函数的简单SFINAE问题

钮承恩
2023-03-14

“我的sfinae发生了什么”Redux:条件模板类成员?

然而,我似乎无法使这个相当简单的SFINAE问题在gcc和MSVC上工作:

#include <type_traits>
#include <iostream>

template<typename A, typename B>
class Test {
public:

  template<typename X=A, typename = typename std::enable_if<std::is_same<X, void>::value, void>::type >
  void foo() {
    std::cout << "A";
  }

  template<typename X=A, typename = typename std::enable_if<!std::is_same<X, void>::value, void>::type >
  void foo() {
    std::cout << "B";
  }


};

int main(int argc, char **argv) {

  Test<int, float> t;

  t.foo();

  return 0;
}

实际结果:

main.cpp:15:8: error: 'template<class A, class B> template<class X, class> void Test<A, B>::foo()' cannot be overloaded with 'template<class A, class B> template<class X, class> void Test<A, B>::foo()'
   15 |   void foo() {
      |        ^~~
main.cpp:10:8: note: previous declaration 'template<class A, class B> template<class X, class> void Test<A, B>::foo()'
   10 |   void foo() {
      |        ^~~
main.cpp:15:8: error: 'template<class A, class B> template<class X, class> void Test<A, B>::foo()' cannot be overloaded with 'template<class A, class B> template<class X, class> void Test<A, B>::foo()'
   15 |   void foo() {
      |        ^~~

main.cpp:10:8: note: previous declaration 'template<class A, class B> template<class X, class> void Test<A, B>::foo()'
   10 |   void foo() {
      |        ^~~

main.cpp: In function 'int main(int, char**)':

main.cpp:26:9: error: no matching function for call to 'Test<int, float>::foo()'
   26 |   t.foo();
      |         ^

main.cpp:10:8: note: candidate: 'template<class X, class> void Test<A, B>::foo() [with X = X; <template-parameter-2-2> = <template-parameter-1-2>; A = int; B = float]'
   10 |   void foo() {
      |        ^~~

main.cpp:10:8: note:   template argument deduction/substitution failed:

main.cpp:9:26: error: no type named 'type' in 'struct std::enable_if<false, void>'
    9 |   template<typename X=A, typename = typename std::enable_if<std::is_same<X, void>::value, void>::type >
      |                          ^~~~~~~~

我想要的是基于一个模板参数实现一个不同的(附加的)成员函数。但是,我似乎不能使enable_if依赖于类模板类型,但我不确定为什么。根据链接的线程,上面的代码看起来是正确的。你能解释一下为什么这不起作用吗?

实时链接

共有1个答案

弘阳德
2023-03-14

以下是C++17版本:

template<typename X=A>
std::enable_if_t<std::is_same_v<X, void>> foo() {
    std::cout << "A";
}

template<typename X=A>
std::enable_if_t<!std::is_same_v<X, void>> foo() {
    std::cout << "B";
}

(enable_if的默认类型是void,它用作函数的类型)

如果,您也可以使用constexpr:

void foo() {
    if constexpr (std::is_same_v<A, void>) {
        std::cout << "A";      
    } else {
        std::cout << "B";
    }
}
template<typename X=A>
typename std::enable_if<std::is_same<X, void>::value>::type foo() {
    std::cout << "A";
}

template<typename X=A>
typename std::enable_if<!std::is_same<X, void>::value>::type foo() {
    std::cout << "B";
}

 类似资料:
  • 在阅读了诸如sfinae关于在类主体之外定义的成员函数(这不是同一个问题)等问题之后,我仍然没有找到在使用sfinae方法仅使用算术类型启用类时在类声明之外定义成员函数主体的好方法。 在本例中,我得到错误:

  • 我一直试图理解C++选择模板的方式。即,考虑以下代码示例: 前两个函数(test1)工作正常(为什么?): 一个常见的错误是声明两个仅在默认模板参数上不同的函数模板。这是非法的,因为默认模板参数不是函数模板签名的一部分,并且用相同的签名声明两个不同的函数模板是非法的。 所以看起来是这样的。但是,我看不出与前两个函数有太大的不同,前两个函数也有默认的模板参数。因此,我们对默认值(test1-work

  • 其中T是模板参数。它是这样实现的: 并按预期工作。当我试图将和的定义移到类体之外时,问题就出现了,如下所示: 在箭头标记的一行表达了它的不满:

  • 我是编写模板元编程代码的新手(而不是仅仅阅读它)。所以我遇到了一些新手问题。其中一个很好地总结了这个名为“我的SFINAE发生了什么?”的非SO帖子,我将C 11化为这样: (注意:我给这些方法起了不同的名字,只是为了帮助我在这个“思想实验”示例中进行错误诊断。请参阅@R. MartinhoFernandes关于为什么您实际上不会在非重载的实践中选择这种方法的注释。) @Alf说SFINAE发生的

  • 5.1. 函数声明 函数声明包括函数名、形式参数列表、返回值列表(可省略)以及函数体。 func name(parameter-list) (result-list) { body } 形式参数列表描述了函数的参数名以及参数类型。这些参数作为局部变量,其值由参数调用者提供。返回值列表描述了函数返回值的变量名以及类型。如果函数返回一个无名变量或者没有返回值,返回值列表的括号是可以省略的。如

  • 条款19: 分清成员函数,非成员函数和友元函数 成员函数和非成员函数最大的区别在于成员函数可以是虚拟的而非成员函数不行。所以,如果有个函数必须进行动态绑定(见条款38),就要采用虚拟函数,而虚拟函数必定是某个类的成员函数。关于这一点就这么简单。如果函数不必是虚拟的,情况就稍微复杂一点。 看下面表示有理数的一个类: class rational { public: rational(int nume