使用constexpr initializer_list构造函数时,MSVC无法编译

Man*_*ans 3 c++ initializer-list visual-c++ constexpr c++11

为什么Microsoft Visual C++在编译以下代码时失败?:

template <typename T>
struct slice
{
    size_t length;
    T *ptr;

    constexpr slice(std::initializer_list<T> list)
        : length(list.size()), ptr(list.begin()) {}
};

static_assert(slice<const int>({ 1, 2, 3 }).length == 3, "!!");
Run Code Online (Sandbox Code Playgroud)

我得到的错误是:

1>test.cpp(12): error C2131: expression did not evaluate to a constant
1>         visual studio 14.0\vc\include\initializer_list(50): note: failure was caused by an undefined arithmetic operation
Run Code Online (Sandbox Code Playgroud)

initializer_list所有方法的实现都标记了constexpr,看起来它对我来说应该没问题......也许它只是一个编译器问题?

Rak*_*111 8

TL; DR:这是一个编译器 标准问题, 因为你的代码编译得很好 gcc 6.3.1和clang 3.9.1都编译了你的代码.


在C++ 11中,没有标记其中一个方法constexpr,因此您无法在其中使用它static_assert.

您必须注意Visual Studio 2015没有完全constexpr支持.请参阅本文中的C++ 14核心语言功能 表.它只有C++ 11版本的std::initializer_list实现,它没有任何constexpr功能.

小更新:看起来标准中的错误措辞会导致非常数std::initializer_list:

从§18.9.2(强调我的):

类型的对象initializer_list<E>提供对类型对象数组的访问const E.[注意:一对指针或一个指针加上一个长度将是明显的表示initializer_list.initializer_list用于实现8.5.4中指定的初始化列表.复制初始化列表不会复制基础元素.
- 尾注]

因此,不要求实现的私有成员是initializer_list非易失性文字类型; 然而,因为他们提到他们相信一对指针或一个指针和一个长度将是"明显的代表",他们可能不会认为有人可能会把非文字的东西放在其中initializer_list.

(从这个答案无耻地复制.)它更深入,关于为什么你不能std::initializer_list在constexpr上下文中使用.

这已在Visual Studio 2017中"修复".