7

I was trying to write an compile-time valarray that could be used like this:

constexpr array<double> a = { 1.0, 2.1, 3.2, 4.3, 5.4, 6.5 };

static_assert(a[0] == 1.0, "");
static_assert(a[3] == 4.3, "");

static_assert(a.size() == 6, "");

I managed to do it with the following implementation and it works fine (with GCC 4.7):

#include <initializer_list>

template<typename T>
struct array
{
    private:

        const std::size_t _size;
        const T* _data;

    public:

        constexpr array(std::initializer_list<T> values):
            _size(values.size()),
            _data(values.begin())
        {}

        constexpr auto operator[](std::size_t n)
            -> T
        {
            return _data[n]
        }

        constexpr auto size() const
            -> std::size_t;
        {
            return _size;
        }
};

Even though it works fine for me, I am not sure about the behaviour of std::initializer_list and may use some that are undefined behaviour.

constexpr for std::initializer_list constructor, begin and size is fine even though it is not strictly speaking C++11 since N3471 recently got adopted and made it to the standard.

Concerning the undefined behaviour, I am not sure whether the underlying array of the std::initializer_list will live or if not, whether there is a mean to have it live longer than only array's constructor. What do you think?

EDIT: I may not have been clear, but I do not really care about the actual array. What really interests me is the behaviour of std::initializer_list and its underlying array at compile-time.

1 Answer 1

7

Your current code should not compile according to current C++11 rules. When compiled with clang 3.2 I get the following error:

source.cpp:33:28: error: constexpr variable 'a' must be initialized by a constant
expression 
constexpr array<double> a = { 1.0, 2.1, 3.2, 4.3, 5.4, 6.5 };
                        ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This is because std::initializer_lists ctors and member functions begin and end are not labeled constexpr. However, there already is a proposal to change this. BTW, libstdc++ already marks these as constexpr.

Now the next problem is the lifetime of the underlying array of std::initializer_list. This is explained in 8.5.4p6:

The array has the same lifetime as any other temporary object (12.2), except that initializing an initializer_list object from the array extends the lifetime of the array exactly like binding a reference to a temporary.

This means that the underlying array has the same lifetime as values object, and expires at the end of your array constructor when it exits. Therefore, _data is pointing to expired memory and _data[n] is undefined behavior.

Sign up to request clarification or add additional context in comments.

1 Comment

Ok, thanks, I could not find the revelant part of the standard about the lifetime :) I already knew for constexpr, that's why I talked about N3471 which no only got proposed but also got accepted.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.