Manu Evans
Manu Evans

Reputation: 1178

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?

Upvotes: 3

Views: 1302

Answers (2)

Michael Haephrati
Michael Haephrati

Reputation: 4235

Try setting Conformance mode on, and it will eliminate the compilation errors. enter image description here

Upvotes: 0

Rakete1111
Rakete1111

Reputation: 48998

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.

Upvotes: 8

Related Questions