libstdc ++实现std::experimental::optional
uses一种SFINAE技术,似乎与gcc一起使用,但不与clang一起使用。
我已将其缩减为以下最小例子:
// Standard enable_if class
template <bool> struct enable_if {};
template <> struct enable_if<true> { typedef int type; };
// An example trait
template <typename> struct trait { static const bool value = true; };
// Overload to call if the trait is false
template<typename T, typename enable_if<!trait<T>::value>::type...>
void foo(T);
// Overload to call if the trait is true
template<typename T, typename enable_if<trait<T>::value>::type...>
void foo(T);
// Call site
void bar() {
foo(0);
}
这用gcc编译,但不用clang编译。 Clang的错误是:
test.cpp:18:5: error: call to 'foo' is ambiguous
foo(0);
^~~
test.cpp:11:6: note: candidate function [with T = int, $1 = <>]
void foo(T);
^
test.cpp:14:6: note: candidate function [with T = int, $1 = <>]
void foo(T);
^
显然,gcc将第一个重载作为候选者丢弃,因为它在将T = int
转换为typename enable_if<!trait<T>::value>::type
时遇到替换失败。
谁是对的?
答案 0 :(得分:0)
我没有太多经验来解释C ++规范关于模板参数推导的内容,但我会对此进行一次尝试:
gcc是对的。
[temp.deduct] p5
说(强调我的):
从默认值推导或获取所有模板参数时 模板参数,全部使用模板中的模板参数 模板的参数列表和功能类型将替换为 相应的推导或默认参数值。如果 如上所述,替换导致无效类型,类型 扣除失败。
在T
中使用typename enable_if<!trait<T>::value>::type...
是在模板的模板参数列表中使用模板参数;由于上面的段落说所有这样的用法被替换为相应的参数值,所以需要执行此替换,尽管事实上没有模板参数绑定到此参数包。