静态可变参数模板友元函数是否符合C++标准?
问题
我需要确保类始终以shared_ptr的形式被实例化,因此采用工厂模式编写了代码。这段代码能在GCC中编译通过,但在MSVC中编译失败。我发现两种修改方式可以解决MSVC的编译问题:
- 将
create_shared移出类作为自由函数 - 移除模板的可变参数
想明确:这段代码是否属于不合规的C++程序,还是MSVC编译器存在问题?
示例代码
#include <memory> class Base { public: template <typename Device, typename... Args> static std::shared_ptr<Device> create_shared(Args&&... args) { return std::shared_ptr<Device>(new Device(std::forward<Args>(args)...)); } protected: Base() = default; }; class Derived : public Base { private: template <typename Device, typename... Args> friend std::shared_ptr<Device> Base::create_shared(Args&&... args); Derived() : Base() { } }; int main(int, char**) { auto d{Base::create_shared<Derived>()}; }
分析与结论
这段代码完全符合C++标准,编译失败是MSVC编译器的实现缺陷导致的。
具体原因:
- 当
Derived将Base的可变参数模板成员函数create_shared声明为友元时,MSVC在解析该友元声明的模板参数绑定关系时存在逻辑错误,无法正确识别create_shared的实例化有权访问Derived的私有构造函数。 - GCC对这种友元模板的解析严格遵循标准,能够正确处理权限校验,因此可以正常编译。
你提到的两种解决方法都是绕开MSVC缺陷的可行方案:
- 将
create_shared改为自由函数后,友元声明的结构更简单,MSVC能正确处理权限检查。 - 移除可变参数后,模板参数列表简化,避免触发MSVC的解析错误逻辑。
内容的提问来源于stack exchange,提问作者SupAl
相关产品推荐
相关产品推荐

