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

C++17中编译器如何推导带转发引用的类模板?

关于C++17类模板推导与转发引用构造函数的解析

咱们一步步拆解你这个问题,核心是搞清楚**类模板推导(CTAD)**在面对带转发引用的模板构造函数时的逻辑,以及那个条件编译的非模板构造函数带来的差异。

先看没有定义ON宏的场景

此时你的MyAbs结构体只有一个模板构造函数:

template<typename U>
MyAbs(U&& u) : t(std::forward<T>(u)) { cout << "template" << endl;}

这里的U&&是转发引用,但问题在于:编译器没办法从构造函数的模板参数U推导出类模板参数T——因为两者之间没有明确的推导关联。构造函数里的std::forward<T>(u)用到了T,但此时T还是未知的,编译器找不到任何能把U和T绑定起来的线索。

举个例子,如果你写MyAbs obj(5);,编译器能推导出U是int(因为5是int右值),但完全不知道T应该是什么类型,所以会直接编译失败。这种情况下你必须显式指定类模板参数,比如MyAbs<int> obj(5);才能正常编译。

定义ON宏后的场景

此时多了一个非模板构造函数:

MyAbs(const T& t) : t(t) {}

这就给CTAD提供了关键的推导依据:

  1. 第一步:推导类模板参数T
    当你写MyAbs obj(5);或者int x=3; MyAbs obj(x);时,编译器会优先通过这个非模板构造函数来推导T——实参的类型会直接映射到T。比如传入int类型的实参,T就被推导为int。

  2. 第二步:重载决议选择构造函数
    一旦T确定了,编译器就会在两个构造函数中选最匹配的那个:

    • 传入右值(比如5):模板构造函数会推导U为int,参数是int&&(完美匹配右值),而非模板构造函数的参数是const int&。此时模板构造函数匹配度更高,会被调用,输出template。
    • 传入非const左值(比如int x=3;):模板构造函数会推导U为int&,经过引用折叠后参数是int&(完美匹配非const左值),而非模板构造函数是const int&。模板构造函数更匹配,所以还是会调用它,输出template。
    • 传入const左值(比如const int x=3;):两个构造函数的参数都是const int&,此时非模板函数的优先级高于模板函数,会调用非模板构造函数,不会输出template。

如何让无ON宏的场景支持CTAD?

如果不想依赖那个非模板构造函数,你可以给类模板添加显式推导指引(Deduction Guide),直接告诉编译器怎么从构造函数实参推导T:

template<typename U>
MyAbs(U&&) -> MyAbs<std::decay_t<U>>;

这里用std::decay_t<U>来去除实参的引用、cv限定符,保证不管传入左值、右值还是const类型,T都是对应的原始值类型(比如传入int&或const int&&,T都是int)。添加这个推导指引后,MyAbs obj(5);就能正常推导T为int,调用模板构造函数了。

内容的提问来源于stack exchange,提问作者Stephen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:23:41