如何在constexpr函数中使用非静态类成员获取数组成员大小
问题根因
你的代码报错的核心原因是常量表达式语境的语法限制:
- 空指针解引用
((Foo*)0)->anarray属于未定义行为,C++标准明确禁止在常量表达式中出现这类操作 std::declval<>仅允许用于sizeof、decltype等不求值上下文,没有实际运行时实现,不能作为需要求值的函数参数传入- 即使第一种写法在部分编译器上可编译,也依赖于编译器的特殊优化,因为你的
Foo构造函数包含运行时输出逻辑,不属于合法的常量表达式构造,写法本身不具备可移植性。
解决方案
不需要实例化类对象,直接通过数组类型萃取即可获取大小,有以下几种实现方式:
方案1:使用标准库类型萃取(最简单,C++11及以上支持)
直接用<type_traits>头文件中的std::extent获取数组长度:
#include <type_traits> #include <iostream> struct Foo { Foo() { std::cout << "Non-constexpr constructor\n"; } int anarray[16]; }; // 直接通过成员类型获取大小,完全不需要实例化Foo constexpr size_t arraySize = std::extent_v<decltype(Foo::anarray)>;
如果需要兼容更老的C++版本,可以写为std::extent<decltype(Foo::anarray)>::value。
方案2:兼容任意类成员数组的通用萃取模板
如果需要封装成通用工具,可以实现如下模板,支持传入任意类的数组成员指针获取大小:
template <auto MemberPtr> struct member_array_size; template <typename ClassType, typename ElementType, size_t N, ElementType ClassType::*MemberPtr> struct member_array_size<MemberPtr> { static constexpr size_t value = N; }; // 使用方式 constexpr size_t arraySize = member_array_size<&Foo::anarray>::value;
方案3:适配你原有调用习惯的宏封装
如果你希望保留类似原有代码的调用形式,可以封装为宏,内部使用不求值上下文规避常量表达式限制:
#include <type_traits> #include <utility> #define GET_ARRAY_SIZE(arr) std::extent_v<std::remove_reference_t<decltype(arr)>> // 原有三种写法都可以正常编译 constexpr int size1 = GET_ARRAY_SIZE(Foo().anarray); constexpr int size2 = GET_ARRAY_SIZE(((Foo*)0)->anarray); constexpr int size3 = GET_ARRAY_SIZE(std::declval<Foo>().anarray);
内容的提问来源于stack exchange,提问作者Zebrafish
相关产品推荐
相关产品推荐

