为何X({})可初始化对象,而X(PrivateTag{})却无法通过编译?
为什么
auto x3 = X({});能通过编译而auto x2 = X(X::PrivateTag{});不行? 核心原因在于C++访问控制针对的是“名字的访问”,而非类型本身的隐式使用,两者的初始化语义存在关键差异:
对于
auto x2 = X(X::PrivateTag{});:
你需要显式写出X::PrivateTag这个类型名来构造临时对象,但PrivateTag是X的私有成员结构体,外部作用域(比如main函数)没有权限访问这个名字,因此编译器直接报错。对于
auto x3 = X({});:
这是列表初始化的调用方式,编译器会通过重载解析匹配到公有的构造函数X(PrivateTag)。此时编译器会隐式创建一个PrivateTag临时对象(利用其默认构造函数),但整个过程不需要在外部作用域显式引用PrivateTag的名字——访问权限检查只针对你写出的名字,而非编译器隐式推导使用的类型,因此这个调用是合法的。
简单来说:前者需要你“说出”私有类型的名字,而后者只需要借助公有的构造函数,让编译器自动完成私有类型对象的隐式构造,绕开了对私有类型名字的直接访问。
对应的代码示例:
#include <memory> class X { struct PrivateTag {}; // 默认构造函数非explicit public: X(PrivateTag) {} static auto Create() -> std::unique_ptr<X> { return std::make_unique<X>(PrivateTag{}); } }; int main() { auto x1 = X::Create(); // 合法:推荐的创建方式 //auto x2 = X(X::PrivateTag{}); // 错误:无法访问私有结构体名字 auto x3 = X({}); // 合法:借助列表初始化隐式构造参数 }
内容的提问来源于stack exchange,提问作者markv
相关产品推荐
相关产品推荐

