Visual C++完美转发编译错误:为何VS2017编译失败,GCC/Clang正常?
为什么这段完美转发的代码在Visual Studio 2017中无法编译?
你碰到的是Visual Studio 2017 15.7.1版本里的编译器bug——这段代码在Clang和G++里能正常编译,就是因为它们正确处理了模板参数推导和完美转发的逻辑,而VS的这个版本在这部分存在逻辑错误。
错误原因分析
当你调用v.emplace_back(123)时,std::vector::emplace_back会尝试推导构造Bar所需的参数。VS的编译器在这里犯了一个错误:它错误地将Bar的模板构造函数和Foo的拷贝构造函数进行了匹配,导致试图用Bar对象去构造Foo,而不是把123正确转发给Foo的int类型构造函数。
具体来说,编译器错误推导了模板参数,让std::forward的目标类型变成了Bar,而非传入的int,进而触发了Foo::Foo(const Foo&)的调用,但此时传入的参数是Bar类型,自然无法转换成int,于是就出现了你看到的C2664错误。
临时修复方案
你可以用以下几种方法绕过这个bug:
- 给
Bar的模板构造函数添加约束,避免它被错误地当作拷贝构造候选:#include <type_traits> // 需要包含这个头文件 struct Bar { template <class... Args, class = std::enable_if_t<!std::is_same_v<std::decay_t<Args>..., Bar>>> Bar(Args&&... args) : foo(std::forward<Args>(args)...) {} Foo foo; }; - 显式声明
Bar的拷贝构造函数,让编译器明确区分模板构造和拷贝构造:struct Bar { template <class... Args> Bar(Args&&... args) : foo(std::forward<Args>(args)...) {} Bar(const Bar&) = default; // 显式默认拷贝构造 Foo foo; }; - 直接升级Visual Studio版本,这个bug在VS2017 15.8及之后的版本已经被官方修复了。
内容的提问来源于stack exchange,提问作者martinus
相关产品推荐
相关产品推荐

