I'm wondering why constexpr functions (std::size in particular) do not work from some non-const context when only type matters.
Let's have a look at two array_size implementations:
- The old good c++98
template <typename T, size_t N>
char (&array_size_helper(const T (&)[N]))[N];
#define array_size(a) sizeof(array_size_helper(a))
- Since C++11 you can use constexpr (the following is
std::sizeimplementation from GCC-8)
constexpr size_t size(const _Tp (&/*__array*/)[_Nm]) noexcept { return _Nm; }
The second version is nice and perfect except it does not work the same way as the first one does. Since first macro is related on sizeof it only cares about types, while constexpr function is much complicated matter.
Consider an example:
struct A
{
int a[10];
};
template <typename T, size_t N>
char (&array_size_helper(const T (&)[N]))[N];
# define array_size(a) sizeof(array_size_helper(a))
int main()
{
A a;
A* new_A = reinterpret_cast<A*>(&a);
static_assert(array_size(a.a) == 10) // OK;
static_assert(array_size(new_A->a) == 10); //OK
static_assert(std::size(a.a) == 10); //OK
static_assert(std::size(new_A->a) == 10); //error: the value of ‘new_A’ is not usable in a constant expression
}
Why is that? Why does std::size care about anything but type? Shouldn't it be re-implemented?