用右值/左值理解模板参数推导
Posted
技术标签:
【中文标题】用右值/左值理解模板参数推导【英文标题】:Understanding template argument deduction with rvalue/lvalue 【发布时间】:2014-03-04 09:03:18 【问题描述】:这是function template does not recognize lvalue的后续报道
让我们玩一下下面的代码:
#include <iostream>
template <class T>
void func(T&&)
std::cout<<"in rvalue\n";
template <class T>
void func(const T&)
std::cout<<"in lvalue\n";
int main()
double n=3;
func<double>(n);
func(n);
打印出来:
in lvalue
in rvalue
我不明白第二次通话中发生了什么。编译器如何 解析模板参数?为什么没有歧义?
【问题讨论】:
您不妨参考标准中的14.8.2。模板参数推导是一个有点复杂的主题。关键是选择了“最佳匹配”,并且T
可以推断为引用类型。
“有点复杂的主题”!我完全同意。顺便问一下,有没有办法让 g++/clang++ 详细说明它在这里做什么?
那个无辜的小部分占据了 15 页,并开发了一个全新的数学符号:-S 但最终它“按照你的想法做”,你只需要在 a 的上下文中接受模板参数作为诚实的类型函数签名。
我发现这个链接很有帮助:isocpp.org/blog/2012/11/…
不,它不打印日志,或者它的作用。但是模板警告/错误非常冗长,如果这就是您的意思的话。
【参考方案1】:
当您说func<double>(n)
时,没有参数推导,因为您指定了参数,因此可以在func(double &&)
和func(const double &)
之间进行选择。前者不可行,因为右值引用不能绑定到左值(即n
)。
只有func(n)
执行参数推导。这是一个复杂的话题,但简而言之,您有以下两个可能的候选人:
T = double &: func(T &&) --> func(double &) (first overload)
T = double: func(const T &) --> func(const double &) (second overload)
第一个重载严格来说更好,因为它需要更少的参数值转换(即从double
到const double
)。
神奇的成分是"reference collapsing",这意味着当T
本身是一个引用类型时T &&
可以是一个左值引用(具体来说,double & &&
变成double &
,这允许第一个推导存在)。
【讨论】:
我认为 Herb Sutter 的文章 Why Not Specialize Function Templates? 也有助于理解这种行为。 @piwi 除了自从引入右值引用以来它已经过时了。 @Kerrek 并没有说得足够清楚:当模板参数推导发生时,func( T &&
中的 &&
) 不是 右值引用,而是一个通用引用,它可以成为右值引用(如果参数是右值)或左值引用(如果参数是左值)。 Scott Meyer 在isocpp.org/blog/2012/11/… 中很好地解释了这一点;这是我针对这个特定问题推荐的文章。
@JamesKanze 我知道&&
的双重含义,具体取决于上下文,但您是对的,Herb Sutter 的文章没有涉及这一点;但是,我发现在“混合”模板和重载时理解解析规则很有用。感谢您的链接!
@piwi 这绝对是一篇有用的文章,而且写得很好。它只是没有解决这里有问题的行为(主要是因为在撰写文章时该行为不存在)。
@JamesKanze:我链接到另一个答案,该答案已经说明了所有细节,我不想在这里重复......以上是关于用右值/左值理解模板参数推导的主要内容,如果未能解决你的问题,请参考以下文章