我已阅读以下主题:
no type named ‘type’ in ‘struct std::enable_if<false, void>
Selecting a member function using different enable_if conditions
"What happened to my SFINAE" redux: conditional template class members?
但是,我似乎无法在gcc和msvc上解决这个相当简单的SFINAE问题:
#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;
}
实际结果:
A =无效:完全错误:
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() {
| ^~~
A =整数:完全错误:
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 >
| ^~~~~~~~
预期结果
A =无效:输出“ A”
A = int:输出“ B”
我想要的是基于模板参数实现其他(附加)成员函数。
但是,似乎我无法使enable_if
依赖于类模板类型,但是我不确定为什么。根据链接的线程,上的代码似乎正确。
您能解释一下为什么这不起作用吗?
答案 0 :(得分:1)
这是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 if
来实现:
void foo() {
if constexpr (std::is_same_v<A, void>) {
std::cout << "A";
} else {
std::cout << "B";
}
}
C ++ 11:
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";
}
答案 1 :(得分:1)
cppreference中的注释显示出相似之处,并解释了为什么它不起作用:
一个常见的错误是声明两个函数模板,它们的默认模板参数仅不同。这是行不通的,因为声明被视为同一功能模板的重新声明(功能模板等效项中未考虑默认模板参数)。
/* WRONG */ struct T { enum { int_t,float_t } m_type; template <typename Integer, typename = std::enable_if_t<std::is_integral<Integer>::value> > T(Integer) : m_type(int_t) {} template <typename Floating, typename = std::enable_if_t<std::is_floating_point<Floating>::value> > T(Floating) : m_type(float_t) {} // error: treated as redefinition }; /* RIGHT */ struct T { enum { int_t,float_t } m_type; template <typename Integer, std::enable_if_t<std::is_integral<Integer>::value, int> = 0 > T(Integer) : m_type(int_t) {} template <typename Floating, std::enable_if_t<std::is_floating_point<Floating>::value, int> = 0 > T(Floating) : m_type(float_t) {} // OK };
对代码应用相同的修复程序,使其输出所需的B
:
#include <type_traits>
#include <iostream>
template<typename A, typename B>
class Test {
public:
template<typename X = A,std::enable_if_t<std::is_same<X, void>::value, int> = 0>
void foo() {
std::cout << "A";
}
template<typename X=A,std::enable_if_t<!std::is_same<X, void>::value, int> = 0>
void foo() {
std::cout << "B";
}
};
在您的代码中,两个函数模板的唯一区别仅在于它们的默认参数。修复后,第二个参数为int = 0
或替换失败。