Clang-3.2 可以编译并且代码的行为符合预期:
struct have_f { int f(int i) {return 10;} };
struct empty {};
template <class T>
struct outer {
T t;
// if T have f(), define outer_f()
template<class U=decltype(t.f(1))>
int outer_f(int i) { return t.f(i); }
};
int main() {
outer<have_f> o1;
outer<empty> o2;
// to silence unused var warning
return o1.outer_f(10) + sizeof(o2);
}
任何版本的 GCC 都会拒绝:
t.cc:13:6: error: ‘struct empty’ has no member named ‘f’
int outer_f(int i) { return t.f(i); }
^
谁是正确的? Gcc 还是 Clang?
请注意,有类似的问题 https://stackoverflow.com/questions/11566564/using-sfinae-gives-different-results-on-gcc-and-clang,没有真正的答案。
我相信问题是14.6.3 [温度非依赖]:
1 - 模板定义中使用的非依赖名称是使用通常的名称查找找到的,并在使用时绑定。
给出的示例描述了模板定义中的格式错误的表达式“可以[在模板定义中]或在实例化点进行诊断".
默认模板参数(14.1p9)U=decltype(t.f(1))
是实例化上下文中的非依赖名称struct outer
(也就是说,它不依赖于它自己的模板的模板参数)因此它对于实例化来说格式不正确struct outer
with T = struct empty
。该标准没有明确描述默认模板参数的求值位置,但唯一合理的结论是它们被视为任何其他构造,并在它们出现时(或者在本例中,在实例化点)进行求值。struct outer
模板)。我认为编译器没有任何余地来延迟对 SFINAE 适用的上下文的非依赖默认模板参数的求值。
幸运的是,解决方案很简单:只需使用默认的模板参数即可U
从属名称:
// if T have f(), define outer_f()
template<class T2 = T, class U=decltype(static_cast<T2 &>(t).f(1))>
int outer_f(int i) { return t.f(i); }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)