为何std::array<T,N>::size()未声明为static?编译异常解析
在C++20的MinGW与MSVC环境中,出现了不符合预期的编译行为:
可正常编译的代码
#include <array> #include <cstdint> void functionArray(std::array<uint8_t, 2> const data) { static_assert(2 == data.size()); }
无法编译的代码
#include <array> #include <cstdint> void functionArray(std::array<uint8_t, 2> const & data) { static_assert(2 == data.size()); }
报错信息:error C2131: expression did not evaluate to a constant
现有解决方案
使用std::tuple_size针对std::array的特化版本,绕开成员函数调用的限制:
#include <array> #include <cstdint> #include <tuple> #include <type_traits> void functionArray(std::array<uint8_t, 2> const & data) { static_assert(2 == std::tuple_size<std::remove_reference_t<decltype(data)>>{}); }
MSVC中std::array::size()的实现
template <class _Ty, size_t _Size> class array { // fixed size array of values public: _NODISCARD constexpr size_type size() const noexcept { return _Size; } };
疑问解答
1. 为何引用类型的std::array调用size()无法在编译期求值?
C++标准对常量表达式的求值有严格限制:即使成员函数是constexpr,调用它的对象必须属于核心常量表达式范畴。函数的引用参数不属于核心常量表达式,哪怕它被声明为const,因此通过该引用调用非static的constexpr成员函数时,无法被编译器认定为常量表达式。
2. 是否因为std::array的引用本身并非constexpr变量,导致成员函数调用中的隐式this阻碍了编译期求值?
是的。调用非static成员函数时,会隐式传递this指针,而此处this指向的是函数的引用参数——该参数不是constexpr对象,不符合常量表达式中对this指针指向对象的要求,因此整个调用无法作为常量表达式参与static_assert的求值。
3. 为何std::array<T,N>::size()未声明为static?
主要是为了保持标准容器接口的一致性。std::array的设计目标是同时兼顾原生数组的性能和标准容器的接口兼容性,比如std::vector、std::list等容器的size()都是非static成员函数。将std::array::size()设计为非static,可以让它无缝适配依赖容器接口的泛型代码(例如范围for循环、标准库算法等),避免因接口不一致导致的泛型代码失效。
补充验证示例
将size()声明为static后,即可通过编译,因为static成员函数不需要依赖this指针,调用时无需对象是constexpr:
#include <cstddef> template <size_t N> struct Blub { static constexpr size_t size() { return N; } }; void blubFunction(Blub<4> const & blub) { static_assert(4 == blub.size()); }
内容的提问来源于stack exchange,提问作者JohannesWilde

