C++ 编译器实际上符合零大小数组 SFINAE 规则吗?

问题描述 投票:0回答:1

大约一两年前,我读到了 C++ 中的 SFINAE 规则。他们特别指出

以下类型错误是 SFINAE 错误:

...

尝试创建 void 数组、引用数组、函数数组、负大小数组、非整数大小数组或大小为零的数组

我决定在我的作业中使用这个规则,但是它不起作用。逐渐减少它,我来到了这个我不理解的小代码示例:

#include <iostream>

template<int I>
struct Char {};

template<int I>
using Failer = Char<I>[0];

template<int I>
void y(Failer<I> = 0) {
    std::cout << "y<" << I << ">, Failer version\n";
}

template<int I>
void y(int = 0) {
    std::cout << "y<" << I << ">, int version\n";
}

int main() {
    y<0>();
    y<1>();
    y<2>();
    y<3>();
}

而且,一些C++编译器似乎也不理解它。我创建了一个 Godbolt 示例,您可以在其中找到三种不同的编译器以不同的方式解决

y
歧义:

  • gcc 报编译错误;
  • clang 选择
    int
    版本(这是我认为符合 SFINAE 规则的版本);
  • icc 选择
    Failer
    版本。

其中哪一个是正确的?到底发生了什么?

c++ sfinae compiler-specific
1个回答
0
投票

好问题。您看到的差异是由于编译器如何解释标准造成的。 C++ 标准确实规定,大小为零的数组会导致 SFINAE 错误。然而,这在某种程度上可以由编译器解释。

  1. GCC:最严格的解释。将零大小数组视为错误,并且不允许 SFINAE 启动。

  2. Clang:更严格地遵循标准。看到零大小数组,触发 SFINAE,并回退到

    int
    版本。

  3. ICC:这绝对是意外行为,并且可能不符合标准。它不应该选择零大小数组版本。

就标准而言,Clang 是最接近预期的。 GCC 很严格,但本身并没有错,而 ICC 很可能是错误的。

对于可移植代码,最好不要依赖这种特定的 SFINAE 机制,因为编译器行为各不相同。

© www.soinside.com 2019 - 2024. All rights reserved.