请考虑以下示例(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中的错误?
答案 0 :(得分:4)
这是由fixed retroactively的语言缺陷引起的。尽管T
= S
在每个声明中立即被替换,但是没有理由(现在,抽象对于函数 type 并不重要) std::back_insert_iterator<S>
直到重载解析(它需要知道如何构造)为止,这永远不会发生,因为在为未命名模板参数准备默认值时推导失败。标准中有一个similar example涉及一个返回类型,如果推导在检查之前没有失败(在这种情况下为替代),这将是一个硬错误。
答案 1 :(得分:1)
看起来确实应该编译,因为出于这种原因应该拒绝整个函数,并且编译器不应继续实例化该函数的参数模板。
但是,clang编译了这段代码,而gcc 8.3拒绝了它(我的系统上没有gcc 9),因此看起来可能是一个错误。不过,该错误已在gcc 9中解决。
#include <type_traits>
template <typename T>
struct falsy : std::false_type {};
template <typename T>
struct back_insert_iterator {
back_insert_iterator&
operator=(typename T::value_type&& __value)
{
}
};
template <
typename T,
typename std::enable_if<falsy<T>::value, int>::type = 0>
void f(back_insert_iterator<T>) {
back_insert_iterator<T>::value;
}
template <typename T>
void f(T) { }
struct S {};
int main() {
S s;
f<S>(s);
}