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

可变参数模板中阻止右值引用的困惑:为何与std::cref表现不同?

为什么可变参数模板的delete重载在混合左值右值参数时不触发错误?

核心原因:重载决议中模板可行性的判断

先看std::cref的单参数情况

std::cref的两个重载:

template< class T >
std::reference_wrapper<const T> cref( const T& t ) noexcept;
template< class T >
void cref( const T&& ) = delete;

当传递右值(比如cref(std::string("test")))时:

  • 两个模板都能推导成功:第一个模板的const T&可以绑定右值,第二个模板的const T&&也可以绑定右值。
  • 重载决议会优先选择更匹配的版本:右值绑定到右值引用(const T&&)的匹配度高于绑定到const左值引用(const T&),因此会选中被delete的重载,触发编译错误。

再看你的可变参数foo模板情况

你的两个重载:

template<typename ... Ts>
void foo(const Ts& ... ts) { }

template<typename ... Ts>
void foo(const Ts&& ...) = delete;

关键在于当存在左值参数时,被delete的模板会直接变成不可行:

案例1:foo<std::string, std::string>(a, "sss")

这里显式指定了Ts为std::string, std::string:

  • 第一个重载的参数是const std::string&, const std::string&:
    • 第一个实参a是左值,可以直接绑定到const std::string&;
    • 第二个实参"sss"会隐式转换为std::string临时对象(右值),也能绑定到const std::string&,因此这个重载可行。
  • 第二个重载的参数是const std::string&&, const std::string&&:
    • 第一个实参a是左值,而左值无法绑定到右值引用(哪怕是const的),因此这个重载对第一个参数不兼容,整个模板直接被排除在候选集之外。
  • 最终只有第一个重载可行,编译通过。

案例2:foo<std::string, std::string>("aaaa", "sss")

两个实参都是字符串字面量,会转换为std::string右值:

  • 两个重载都可行:第一个的const std::string&可以绑定右值,第二个的const std::string&&也可以绑定右值。
  • 重载决议选择匹配度更高的第二个重载(右值绑定到右值引用),触发delete错误。

总结

单参数场景下,右值可以同时匹配两个重载,因此delete版本会被选中;但可变参数场景中,只要有一个左值参数,delete版本就会因为参数不兼容被排除,只能选择第一个重载。这是C++重载决议中模板可行性优先于匹配度的规则导致的:如果一个模板在某个参数上无法绑定实参,就会直接被淘汰,不会进入后续的匹配度比较环节。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 01:35:24