Blake Preston
Blake Preston

Reputation: 176

Can template deduction guides call constexpr functions?

I have my own fixed-size array type I want to be constexpr constructible from an std::initializer_list without having to explicitly define the size template argument.

I thought I'd be able to use a template deduction guide but it looks like it's not treating std::initializer_list::size() as a constexpr function for it.

Here's an example of trying to make a deduction guide for std::array (which is similar to my type and has the same problem):

namespace std
{
    template<typename T> array(initializer_list<T> initialiserList) -> array<T, initialiserList.size()>;
}
static constexpr std::array myArray = {1,2,3};
static constexpr std::array myArray2 = {{1,2,3}};

I've tried on MSVC and Clang, both give roughly the same errors: myArray has an error complaining about too many arguments to the function. myArray2 says "substitution failure [with T = int]: non-type template argument is not a constant expression"

I tried putting constexpr in front of the deduction guide or the function argument but neither appears to be allowed, so it appears that the deduction guide is invalid even though it should work fine in a constexpr context.

Is there a way to make this work without going down the make_array() route?

Upvotes: 14

Views: 1019

Answers (3)

max66
max66

Reputation: 66200

Is there a way to make this work without going down the make_array() route?

Why don't you try with the following deduction guide ?

template <typename T, std::size_t N>
array(T const (&)[N]) -> array<T, N>;

This way, the argument in myArray2 = {{1,2,3}} isn't interpreted as a std::initializer_list (that as argument can't be considered constexpr, so it's size() can't be used for a template argument) but as a C-style array.

So can be deduced, as template arguments, type and size (T and N) and also the size (N) can be used as template argument.

Upvotes: 8

Barry
Barry

Reputation: 302708

You can do:

template <class T, class... U>
array(T, U...) -> array<T, 1 + sizeof...(U)>;

The problem is not that you cannot call constexpr functions in deduction guides. You can. This example is ridiculous, but works:

constexpr size_t plus_one(size_t i) { return i + 1; }

template <class T, class... U>
array(T, U...) -> array<T, plus_one(sizeof...(U))>;

The problem is that function parameters are not constexpr objects, so you cannot invoke constexpr member functions on them if those member functions read kind of local state.

Upvotes: 12

Jarod42
Jarod42

Reputation: 217085

Parameter/argument values are not constexpr.

You might use variadic template to know size at compile time, or type with know size (std::array or C-array reference).

Upvotes: 2

Related Questions