Consider the following function:
template <size_t S1, size_t S2>
auto concatenate(const std::array<uint8_t, S1> &data1,
const std::array<uint8_t, S2> &data2)
{
std::array<uint8_t, data1.size() + data2.size()> result; // <<< error here
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.
Unfortunately, the standard states that in a class member access expression The postfix expression before the dot or arrow is evaluated;63 [expr.ref]/1. A postfix expression is a
in a.b
. The note is really interesting because this is precisely the case here:
63) If the class member access expression is evaluated, the subexpression evaluation happens even if the result is unnecessary to determine the value of the entire postfix expression, for example if the id-expression denotes a static member.
So data
is evaluated even if it would not be necessary and the rule fore constant expression applies on it too.