C++17中如何将copy initialization设为私有以保留C++14原有语义?
问题根因
你遇到的版本行为差异是C++17引入的强制复制消除特性导致的:当用同类型的纯右值初始化对象时,编译器会直接在目标对象的内存地址上构造对象,完全省略拷贝/移动构造函数的调用,因此就算拷贝构造声明为私有,也不会触发访问权限检查,直接通过编译。
解决方案(不修改foo返回类型,兼容C++11及所有后续版本)
给类A添加一个仅内部可访问的私有标签类型,所有构造函数都必须传入这个标签才能调用,修改后代码如下:
struct A { static A foo() { // 成员函数可以访问私有标签,构造合法 return A(PrivateTag{}); } private: // 私有标签类型,外部代码无法访问 struct PrivateTag {}; // 所有构造函数都要求传入私有标签 explicit A(PrivateTag) {} A(const A&) = default; A(A&&) = default; }; int main() { // 编译失败:符合预期语义 A a = A::foo(); // 合法:仅绑定引用,不需要构造新的A对象,满足代理类使用需求 const A& lref = A::foo(); A&& rref = A::foo(); }
适配原理
- C++14及更早版本:
A a = A::foo()需要调用私有的拷贝构造函数,访问权限不足报错,和原有语义完全一致 - C++17及之后版本:强制复制消除会直接在
a的地址调用A(PrivateTag)构造函数,但PrivateTag是私有类型,外部代码无法访问,同样触发编译错误 - 完全保留了
foo返回A的接口不变,同时支持用户正常绑定引用到返回的临时对象,符合代理类的设计目标
内容的提问来源于stack exchange,提问作者Simeon
相关产品推荐
相关产品推荐

