标题看起来很复杂,但我们的测试用例实际上是真实案例的最小示例。
我们有一些代码想要根据模板参数选择方法的实现。我们在清理过程中定义了条件enable_if_t
使用 using 子句,并且下一步想要将定义排除在外,这产生了以下代码:
#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;
}
Gcc 不接受它,而 clang 接受:https://godbolt.org/g/Gfm1tw 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 应该能够使用它吗?
EDIT:感谢来自的输入@VTT https://stackoverflow.com/users/7860670/vtt我们发现,差异在于typename
外行声明中的关键字typename A<T>::template is_int_or_float<U>*
。删除它会使 gcc 编译并 clang 拒绝代码。
因此,问题可以重新表述和简化:在这种情况下, typename 是必需的还是允许的?