C++20中非类型模板参数为何仅允许公有成员?
为何字面类作为非类型模板参数时不允许私有成员?
当将以下代码中DoubleString类的p成员设为private时,会触发编译错误:
#include <algorithm> template<std::size_t N> struct DoubleString { constexpr DoubleString(char const(&pp)[N]) { std::copy(std::cbegin(pp), std::cend(pp), std::begin(p)); std::copy(std::cbegin(pp), std::cend(pp), std::begin(p) + N - 1); } constexpr auto data() const { return p; } //private: //取消注释此处会触发错误 char p[N + N - 1]{}; }; template<DoubleString A> constexpr auto operator""_x2() { return A.data(); } int main() { constexpr auto str = "Hello"_x2; std::cout << str; }
根据cppreference的规定:非类型模板参数若为结构类型(字面类类型),需满足所有基类和非静态数据成员均为公有、非可变,且成员类型为结构类型或其数组。请问为何不允许私有成员?
原因解析
非类型模板参数的处理完全发生在编译阶段,编译器需要直接、完整地访问该类实例的所有内部状态,才能完成模板实例化、编译期值计算与常量存储。
编译期实例化的权限限制:当
DoubleString作为非类型模板参数时,编译器需要在类作用域之外(模板推导、实例化阶段)直接初始化该类的实例,比如把字符串字面量"Hello"转换成DoubleString对象。如果p是私有成员,编译器此时没有访问权限——私有成员的访问仅允许类内部成员函数或友元,而模板参数的处理逻辑并不在这个范围内,无法通过data()这类成员函数间接完成初始化和值读取。字面类的核心要求:编译期透明性:字面类作为非类型模板参数的核心设计目标是成为编译期可完全公开访问的常量载体。编译器需要确保能在编译期完整获取该类实例的所有数据,才能将其作为模板的编译期参数使用(比如嵌入到生成的机器码中,或用于其他编译期常量计算)。私有成员破坏了这种透明性,编译器无法保证能在编译期完整解析并使用该类实例的状态,因此标准明确禁止这种情况。
内容的提问来源于stack exchange,提问作者fsmoke
相关产品推荐
相关产品推荐

