Vahagn
Vahagn

Reputation: 4850

Call to constexpr function accepting an array fails to compile

Consider this code:

#include <array>

template < int... Ints >
constexpr std::array<int,sizeof...(Ints)> theIntArray = {Ints...};

template < size_t NN >
constexpr void test(const std::array<int,NN>& xx)
{
    theIntArray<xx[0]>;
}

constexpr std::array<int,2> aa = {10,20};

int main()
{
    theIntArray<aa[0]>; // passes
    test(aa); // FAILS ?!

    return 0;
}

In the main() function the first line passes while the second line fails with a strange error message:

error: ‘* & xx’ is not a constant expression
note: in template argument for type ‘int’

I am using gcc-7.0.1 and you can find live example here.

Is this according to the standard or it is a bug? What makes the second line fail while the first line passes?

Upvotes: 1

Views: 214

Answers (2)

TemplateRex
TemplateRex

Reputation: 70556

The difference is that constexpr function parameter do not exist. That is, you cannot do

constexpr auto fun(int x) {
    constexpr y = x;
    return y;
}

and neither can you use a function parameter xx[0] as a non-type template-parameter inside the function. It's different for aa[0] because that is evaluated outside a function.

The only way to do what you want, is to make the function parameter a non-type template parameter. To do that, see the answer by @Yakk where he uses a const-reference to a constexpr array as a non-type template parameter.

Upvotes: 1

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275966

All constexpr functions must be valid with both a constexpr and non-constexpr arguments. Or, in short, the arguments of a constexpr function are not constexpr within the body, but if they are constexpr outside the function body, certian calculations depending on them may be constexpr on return from the function.

theIntArray<xx[0]>;

this is only valid syntax if xx[0] is constexpr, but within the function body xx is not constexpr.

template < size_t NN, std::array<int,NN> const& xx >
constexpr void test()
{
  theIntArray<xx[0]>;
}

live example.

Upvotes: 2

Related Questions