我想知道为什么constexpr函数(特别是std::size)在只涉及类型时无法从某些非const上下文中使用。
让我们来看看两个array_size实现:
- 旧的好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))
自C++11起,你可以使用constexpr(以下是来自GCC-8的std::size实现)。
constexpr size_t size(const _Tp (&/*__array*/)[_Nm]) noexcept { return _Nm; }
第二个版本看起来很好,除了它不能像第一个版本那样正常运行。因为第一个宏与
sizeof
相关,它只关心类型,而constexpr
函数则更加复杂。考虑以下示例:
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
}
为什么会这样?为什么
std::size
除了类型之外还关心其他东西?难道它不应该被重新实现吗?