It is known that std::array::operator[]
since C++14 is constexpr
, see declaration below:
constexpr const_reference operator[]( size_type pos ) const;
However, it is also const
qualified. This causes implications if you want to use the subscript operator of a std::array
in order to assign values to your array at compile time. For example consider the following user literal:
template<typename T, int N>
struct FooLiteral {
std::array<T, N> arr;
constexpr FooLiteral() : arr {} { for(int i(0); i < N; ++i) arr[i] = T{42 + i}; }
};
The above code won't compile if you try to declare a constexpr
variable of type FooLiteral
. This is attributed to the fact that overload resolution rules qualify the non-const qualified, non-constexpr overload of the array's subscript operator as a better match. Thus the compiler complains about calling a non-constexpr
function.
I can't figure out what was the reason for the commitee to declare this overload as const
qualified for C++14, however it seems that the implication is being noticed and there's also a proposal p0107R0 to fix this in the upcomming C++17.
My natural though to overcome this for C++14 was to somehow hack the expression, in order to evoke the correct subscript operator. What I did is the following:
template<typename T, int N>
struct FooLiteral {
std::array<T, N> arr;
constexpr FooLiteral() : arr {} {
for(int i(0); i < N; ++i) {
const_cast<T&>(static_cast<const std::array<T, N>&>(arr)[i]) = T{42 + i};
}
}
};
That is I casted the array to const
reference to evoke the correct subscript operator overload and then I const_cast
the returned object of the overloaded subscript operator to T&
in order remove its const-ness and be able to assign to it.
This works fine, but I know that const_cast
should be used with caution and to be frank I have second thoughts about if this hack can cause undefined behaviour.
Intuitively, I don't think there's a problem, since this const_cast
is taking place at compile time initialization thus, I can't think of an implication that can arise at this state.
But is that so, or am I wrong and this introduce UB to the program?
Q:
Can someone justify if this is a UB or not?
constexpr FooLiteral
, as forconst FooLiteral
, member cannot be modified... – Renata