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?
请注意,有 similar question ,没有真正的答案。
最佳答案
我认为问题出在 14.6.3 [temp.nondep]:
1 - Non-dependent names used in a template definition are found using the usual name lookup and bound at the point they are used.
给出的示例描述了模板定义中格式错误的表达式“可以[在模板定义中]或在实例化时诊断”。
默认模板参数 (14.1p9) U=decltype(t.f(1))
是 struct outer
实例化上下文中的非依赖名称(也就是说,它不依赖于它自己模板的模板参数)所以它对于 struct outer
的实例化是错误的与 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); }
关于c++ - 带有 decltype : bug in clang or gcc? 的 sfinae,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12813351/