简体   繁体   中英

MSVC fails to compile when using a constexpr initializer_list constructor

Why does Microsoft Visual C++ fails when compile the following code? :

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, "!!");

The error I get is:

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

The implementation of initializer_list has all methods marked constexpr , it looks like it should be fine to me... Maybe it's just a compiler issue?

TL;DR : It is a compiler Standard issue, as your code compiles fine with gcc 6.3.1 and clang 3.9.1 both compile your code though.


In C++11, not one of the methods is marked constexpr , and so you can't use it in a static_assert .

You have to note that Visual Studio 2015 doesn't have full constexpr support. See the C++ 14 Core Language Features table in the article. It has only the C++11 version of std::initializer_list implemented, which doesn't have any constexpr functions.

Small update: It looks like a bad wording in the standard can result in a non-constant std::initializer_list :

From § 18.9.2 (emphasis mine):

An object of type initializer_list<E> provides access to an array of objects of type const E . [Note: A pair of pointers or a pointer plus a length would be obvious representations for initializer_list . initializer_list is used to implement initializer lists as specified in 8.5.4. Copying an initializer list does not copy the underlying elements.
—end note]

So there is no requirement for the private members of the implementation of initializer_list to be non-volatile literal types; however, because they mention that they believe a pair of pointers or a pointer and a length would be the "obvious representation," they probably didn't consider that someone might put something non-literal in the members of initializer_list .

(Shamelessly copied from this answer.) It goes a bit more in depth, about why you couldn't use std::initializer_list in a constexpr context.

This has been "fixed" in Visual Studio 2017.

Try setting Conformance mode on, and it will eliminate the compilation errors. 在此输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM