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

带类型推导的模板类构造函数中如何正确使用universal reference

核心原因:万能引用的生效前提

万能引用(转发引用)的本质是模板参数推导过程中的引用折叠,必须同时满足两个条件才能生效:

  • 参数形式必须是T&&
  • 这里的T是当前正在被推导的函数模板参数

你代码中所有报错的场景,本质都是不满足上面的前提:

  • 类A的T&&不是万能引用:T是类的模板参数,实例化类的时候T就已经确定,构造函数的T&&是普通右值引用,只能绑定右值,左值传入自然报错
  • 类B的参数是左值引用,只能绑定左值,右值传入会报错
  • 类C的构造函数本身是模板,但C++17之前类模板的构造函数不会自动推导类的模板参数,写C c1(get_l_value())时编译器不知道类C的模板参数T应该是什么,直接推导失败

正确实现方案

C++17及以上版本(支持类模板实参推导CTAD)

只需要给类C加一条推导指引即可正常使用:

template<class T> struct C {
    // 如果需要完美转发参数到内部可以用std::forward
    template<class T2> C(T2&& a) : m_val(std::forward<T2>(a)) {}
private:
    T m_val;
};

// 新增推导指引,告诉编译器构造参数和类模板参数的对应关系
template<class T2> C(T2&&) -> C<std::decay_t<T2>>;

修改后你示例中c1、c2的调用都可以正常编译,std::decay_t的作用是去掉参数的引用、const/volatile限定符,得到原始类型。

C++11/14版本(不支持CTAD)

可以通过工厂函数绕开类模板参数推导的限制:

template<class T>
C<typename std::decay<T>::type> make_C(T&& val) {
    return C<typename std::decay<T>::type>(std::forward<T>(val));
}

// 调用时不需要手动指定参数
auto c1 = make_C(get_l_value());
auto c2 = make_C(get_r_value());

可编译的完整示例代码
#include <vector>
#include <type_traits>
#include <utility>

template<class T> struct C {
    template<class T2> C(T2&& a) {}
};

template<class T2> C(T2&&) -> C<std::decay_t<T2>>;

template<class T> void foo(T&& a) { }

auto get_r_value() {
    return std::vector<int>(100);
}

std::vector<int>& get_l_value() {
    static std::vector<int> v(100);
    return v;
}

int main() {
    foo(get_r_value()); // ok
    foo(get_l_value()); // ok

    C c1(get_l_value()); // ok
    C c2(get_r_value()); // ok
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 19:00:00