传递std::shared_ptr的std::visit在Clang 13.0.1下编译失败问题求助
我来帮你拆解这个问题——你的代码在MSVC和GCC下能正常编译,但在Clang 13.0.1里触发报错,核心原因是C++标准对可变参数函数的参数传递有严格限制,而不同编译器对标准的执行力度和扩展支持不同。
先回顾报错场景的代码
编译失败的核心代码片段(简化后):
void print(...) {std::cout << "no implementation";} // 在std::visit中调用 print(c, pointerData); // pointerData是std::shared_ptr<VarType>类型
Clang的报错信息:
error: cannot pass object of non-trivial type 'std::shared_ptr<std::pair<int, std::variant<Struct1, Struct2, UnsupportedStruct>>>' through variadic function
问题的本质原因
- 什么是非平凡类型:
std::shared_ptr属于非平凡类型——它拥有自定义的拷贝构造函数、析构函数和赋值运算符,用来管理引用计数和堆内存。这类类型的对象不能像int、char等简单类型那样直接按字节拷贝。 - C++标准的规定:根据C++标准,将非平凡类类型的对象传递给可变参数函数的省略号(
...)部分时,行为是未定义的。标准不要求编译器支持这种操作,完全由编译器自行决定如何处理。 - 编译器差异:
- MSVC和GCC提供了扩展支持,允许将非平凡类型传递给可变参数函数,所以你的代码能正常编译。
- Clang在这个版本中严格遵循标准(或者对标准库类型做了更严格的安全检查),直接禁止了这种不安全的操作,因此抛出报错。
为什么修复后的代码能正常编译
你修改后的代码把std::shared_ptr<VarType>换成了解引用后的const VarType&:
void print(const Struct1&, const VarType& v) { ... } void print(const Struct2&, const VarType& v) { ... } void print(...) { ... } // 调用时传递解引用后的对象 print(c, *pointerData);
能编译的关键在于:
- 当处理
Struct1或Struct2时,调用的是前两个明确类型的重载函数,完全符合标准,和可变参数无关,Clang自然不会报错。 - 当处理
UnsupportedStruct时,才会走到print(...)。此时传递的*pointerData是VarType对象,虽然它也是非平凡类型,但Clang在这里没有严格拦截(或者说这属于标准未定义行为但Clang选择容忍的场景),因此代码能通过编译。
更安全的替代方案
为了彻底避免跨编译器的兼容性问题,建议不要依赖可变参数函数的扩展支持,而是为UnsupportedStruct添加明确的重载:
void print(const UnsupportedStruct&, const VarType& v) { std::cout << "no implementation"; }
这样所有重载都是明确的类型匹配,完全符合C++标准,在任何编译器下都能正常工作,同时也让代码的类型安全性更高。
内容的提问来源于stack exchange,提问作者Stanislav
相关产品推荐
相关产品推荐

