10

Would it be possible to verify that an initializer list that is being passed to a constexpr constructor is a certain size? Or would this only be possible to do at runtime?

This is the idea, but it doesn't work:

struct group
{
        constexpr group(
            std::initializer_list<std::initializer_list<UINT const> const> groups
        )
        {
            static_assert(each_list_size_greater_than_1(groups.begin(), groups.end()));
        }

        constexpr static bool each_list_size_greater_than_1(
            std::initializer_list<std::initializer_list<UINT const> const>::const_iterator const begin
            , std::initializer_list<std::initializer_list<UINT const> const>::const_iterator const end)
        {
            return begin == end || begin->size() > 1 && each_list_size_greater_than_1(begin + 1, end);
        }
};

I've looked at VS2015's std::initializer_list implementation and begin(), end() and size() are all constexpr functions.

1 Answer 1

14

Although the size() of an std::initializer_list<T> can evaluate to a constexpr the size() member won't behave like a constexpr within a constexpr function: it is intentional that objects only behave like constexpr within the constexpr expression where they were introduce but not elsewhere.

For example:

constexpr get_size(std::initializer_list<int> list) {
    constexpr std::size_t csize = list.size(); // ERROR (1)
    std::size_t           size  = list.size(); // OK
    return size;
}

int main() {
    constexpr std::size_t csize = get_size(std::initializer_list<int>{ 1, 2, 3 }); // OK (2)
    // ...
}

In the first case (1) the value which is assumed to yield a constexpr depends on data created before the constexpr starts. As a result, it doesn't evaluate to a constexpr. In the second case (2) the data is defined within the constexpr and, thus, the result can become a constexpr.

I haven't been part of the discussions leading to this design but it seems it is motivated by the desire to prevent constexpr arguments changing the result type of a constexpr function: if the values were constexprs within the function definition, they would also be constexprs in the return value and could, thus, be used as template arguments in the return type. That would lead to different values to constexpr function yielding different types. So far, you can get a different return type only by varying the argument types of a function and/or by changing the number of arguments of a function.

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

2 Comments

What is meant by your last statement: So far, you can get a different return type only be varying the template arguments and/or their number.?
@Adrian: according to the C++ standards at least up to C++1z you cannot create different return types for a function based on the value of the function arguments. You'll need to change the type of the function to change its return type. I do realize you aren't interested in actually changing the return type of a function but rather just use an argument value as a constexpr. However, if an argument value can be used as a constexpr within a function the same value could be used in the return type, thereby making something possible which is currently not allowed.

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.