c++ - 为什么这个 SFINAE 在 gcc 中会报错?

标签 c++ c++11 gcc

考虑以下示例 ( 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/

相关文章:

c++ - 对 TR1 使用 boost 时,boost 数学特殊函数编译错误

c++ - 汇编消息 : no such instruction when Compiling C++

c++ - 如何确保我已经对 std::set 中的每一对元素进行了插入循环操作?

c++ - 在我的小部件应用程序中的 qt mainwindow.ui 窗口中打印文本

c++ - 是否可以用 gcc 编译 c++ 代码?

objective-c - 在没有 Doxygen/编译器警告的情况下记录继承的 Obj-C 方法?

c++ - RegCloseKey() 函数应该只在成功调用 RegOpenKey() 之后使用,还是无条件使用?

c++ - std::vector<Class *> 没有正确构造拷贝

c++ - c++ 11为调用者构造一个对象

c++ - 如何在 C++11 中创建我自己的 initializer_list 类?