这种涉及可变模板的SFINAE技术有效吗
Is this SFINAE technique involving variadic templates valid?
libstdc++对std::experimental::optional
的实现使用了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
时遇到了替换失败。
另一方面,Clang似乎跳过了执行该替换,也许是因为它意识到该参数包上没有绑定任何模板参数。因此,它不会遇到替换失败,第一次过载仍然可行。
谁是对的
我没有太多经验来解释C++规范中关于模板参数推导的内容,但我会尝试一下:
gcc是对的
[temp.deduct] p5
说(强调矿):
当所有模板参数都已从默认值推导或获得时模板参数,所有使用模板中模板参数的模板的参数列表和函数类型被替换为相应的推导或默认参数值。如果替换导致无效的类型,如上所述,类型扣减失败。
typename enable_if<!trait<T>::value>::type...
中T
的使用是对模板的模板参数列表中的模板参数的使用;由于上面的段落说所有这样的使用都被相应的参数值替换,所以需要执行这种替换,尽管没有模板参数绑定到这个参数包。
相关文章:
- 为什么使用SFINAE而不是函数重载
- 如何使用模板函数的函数签名进行SFINAE
- 数据成员SFINAE的C++17测试:gcc vs clang
- 使用在用于SFINAE的void_t中具有参数的方法
- 编译器如何在使用SFINAE的函数和标准函数之间确定两者是否可行
- 提供与TMP和SFINAE的通用接口
- 在C++中样板"冷/never_inline"错误处理技术的最佳方法是什么?
- "Inverse SFINAE"避免模棱两可的过载
- 在 Windows 8/10 技术中完全实时的屏幕捕获,没有延迟
- C++ 关于指针取消引用的技术问题
- 表达式 SFINAE:如何根据类型是否包含具有一个或多个参数的函数来选择模板版本
- 是否有技术原因阻止 Java 中的 final C++ 像 const 一样严格?
- 如何在儿童类中使用SFINAE
- 使用 SFINAE 作为模板参数的编译时递归
- 使用 SFINAE 设计模板方法
- 与SFINAE支票交朋友
- C++许多 SFINAE 风格的过载
- 是否可以混合使用SFINAE和模板专业化?
- 使用SFINAE分辨率区分普通模板参数和模板模板参数的技术
- 这种涉及可变模板的SFINAE技术有效吗