You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:36:07