Consider the following function:
template <size_t S1, size_t S2>
auto concatenate(std::array<uint8_t, S1> &data1, std::array<uint8_t, S2> &data2) {
std::array<uint8_t, data1.size() + data2.size()> result;
auto iter = std::copy(data1.begin(), data1.end(), result.begin());
std::copy(data2.begin(), data2.end(), iter);
return result;
}
int main()
{
std::array<uint8_t, 1> data1{ 0x00 };
std::array<uint8_t, 1> data2{ 0xFF };
auto result = concatenate(data1, data2);
return 0;
}
When compiled using clang 6.0, using -std=c++17, this function does not compile, because the size member function on the array is not constexpr due to it being a reference. The error message is this:
error: non-type template argument is not a constant expression
When the parameters are not references, the code works as expected.
I wonder why this would be, as the size() actually returns a template parameter, it could hardly be any more const. Whether the parameter is or is not a reference shouldn't make a difference.
I know I could of course use the S1 and S2 template parameters, the function is merely a short illustration of the problem.
Is there anything in the standard? I was very surprised to get a compile error out of this.
A call to a constexpr function produces the same result as a call to an equivalent non- constexpr function , except that a call to a constexpr function can appear in a constant expression. The main function cannot be declared with the constexpr specifier.
Like const , it can be applied to variables: A compiler error is raised when any code attempts to modify the value. Unlike const , constexpr can also be applied to functions and class constructors. constexpr indicates that the value, or return value, is constant and, where possible, is computed at compile time.
2) A function defined entirely inside a class/struct/union definition, whether it's a member function or a non-member friend function, is always inline. 3) A function declared constexpr is always inline.
Because you have evaluated a reference. From [expr.const]/4:
An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:
- ...
- an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either
- it is usable in constant expressions or
- its lifetime began within the evaluation of e;
- ...
Your reference parameter has no preceding initialization, so it cannot be used in a constant expression.
You can simply use S1 + S2
instead here.
There has been a bug reported on this issue for clang titled: Clang does not allow to use constexpr type conversion in non-type template argument.
The discussion in it points that this is not really a bug.
An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:
- [...]
- an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either
- it is initialized with a constant expression or
- its lifetime began within the evaluation of e;
- [...]
The above quote is from [expr.const]/2.11 of draft n4659 with emphasis added.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With