标题似乎令人费解,但我们的测试用例实际上是一个真实案例的最小例子。
我们有代码,我们希望根据模板参数选择方法的实现。我们在清理期间使用using子句定义了条件enable_if_t
,并且由于下一步想要将定义置于行之外,这产生了以下代码:
#include <type_traits>
#include <iostream>
#include <string>
template <typename T>
struct A {
template <typename U>
using is_int_or_float = std::enable_if_t< std::is_same<U, int>::value || std::is_same<U, float>::value >;
template<typename U = T, is_int_or_float<U>* = nullptr >
void f();
template<typename U = T, typename std::enable_if_t< std::is_same<U,std::string>::value >* = nullptr >
void f();
};
template <typename T>
template <typename U, typename A<T>::template is_int_or_float<U>* >
void A<T>::f(){
std::cout << "f for int or float\n";
}
template <typename T>
template<typename U, typename std::enable_if_t< std::is_same<U,std::string>::value >*>
void A<T>::f() {
std::cout << "f for string\n";
}
int main () {
A<int> a_int;
A<std::string> a_string;
A<float> a_float;
a_int.f();
a_string.f();
a_float.f();
a_float.f<std::string>();
return 0;
}
当clang执行时,Gcc不接受它:https://godbolt.org/g/Gfm1tw
gcc(和icc)抱怨使用is_int_or_float
定义的方法没有有效的原型。
我不确定clang是否过于混乱,或者gcc应该能够超越依赖类型。
如果我们为其定义切换typename A<T>::template is_int_or_float<U>
,则代码有效:
template <typename T>
template <typename U, std::enable_if_t< std::is_same<U, int>::value || std::is_same<U, float>::value >* >
void A<T>::f(){
std::cout << "f for int or float\n";
}
使用using
是否会更改有关类型匹配的规则,或者gcc是否应该使用它?
编辑:感谢@VTT的输入,我们发现,差异在于外线声明typename
中的typename A<T>::template is_int_or_float<U>*
关键字。删除它会使gcc compile和clang拒绝代码。
所以问题可以改写和简化:在这种情况下是否需要typename或允许这样做?