考虑以下示例 ( https://godbolt.org/z/pSTUZI ):
#include <iterator>
#include <type_traits>
template <typename T>
struct falsy : std::false_type {};
template <
typename T,
typename std::enable_if<falsy<T>::value, int>::type = 0>
void f(std::back_insert_iterator<T>) {}
template <typename T>
void f(T) {}
struct S {};
int main() {
S s;
f<S>(s);
}
用 gcc 8.3 或更早版本编译会报错:
In file included from /opt/compiler-explorer/gcc-8.3.0/include/c++/8.3.0/iterator:63,
from <source>:1:
/opt/compiler-explorer/gcc-8.3.0/include/c++/8.3.0/bits/stl_iterator.h: In instantiation of 'class std::back_insert_iterator<S>':
<source>:19:9: recursively required by substitution of 'template<class T, typename std::enable_if<falsy<T>::value, int>::type <anonymous> > void f(std::back_insert_iterator<_Container>) [with T = S; typename std::enable_if<falsy<T>::value, int>::type <anonymous> = <missing>]'
<source>:19:9: required from here
/opt/compiler-explorer/gcc-8.3.0/include/c++/8.3.0/bits/stl_iterator.h:490:7: error: no type named 'value_type' in 'struct S'
operator=(const typename _Container::value_type& __value)
^~~~~~~~
/opt/compiler-explorer/gcc-8.3.0/include/c++/8.3.0/bits/stl_iterator.h:497:7: error: no type named 'value_type' in 'struct S'
operator=(typename _Container::value_type&& __value)
^~~~~~~~
而 clang 和 gcc 9 编译它没有任何错误。这个例子是对 SFINAE 的正确使用吗?它是 gcc < 9 中的错误吗?
最佳答案
这是由于语言缺陷导致的 fixed retroactively .同时 T
= S
在每个声明中立即被替换,没有理由(现在抽象性对函数类型不重要)实例化 std::back_insert_iterator<S>
直到重载决议(这需要知道一个可能是如何构造的),这永远不会发生,因为在为未命名模板参数准备默认值时推导失败。有一个 similar example在涉及返回类型的标准中,如果推导在检查之前没有失败(在这种情况下通过替换),这将是一个硬错误。
关于c++ - 为什么这个 SFINAE 在 gcc 中会报错?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56436995/