我一直在尝试对递归解压缩的参数包使用完美的转发,这使我意识到我不太了解在通用引用存在下如何为给定函数选择重载的规则。
我的困惑是由一些类似于以下内容的代码引起的:
#include <iostream>
template<class T>
void write(const T& data)
{
std::cout << "Called write(const T& data)" << std::endl;
}
template<class T, class ...U>
void write(T&& obj, U&&... objs)
{
std::cout << "Called write(T&& obj, U&&... objs)" << std::endl;
}
int main(int, char**)
{
int j = 0;
write(j);
return 0;
}
运行时,将选择void write(T&& obj, U&&... objs)
重载,但是如果我将void write(const T& data)
的签名更改为void write(const T data)
,void write(T& data)
或void write(T data)
,则该函数被称为。
为什么没有选择void write(const T& data)
重载,却选择了void write(const T data)
,void write(T& data)
或void write(T data)
?
编辑:我最初虽然认为该问题可能与使用std::forward
有关;但是,这似乎更多是通用参考的结果。我的原始示例如下:
#include <iostream>
void write()
{
std::cout << "Writing nothing" << std::endl;
}
void write(const char* data)
{
std::cout << "Writing const char*: " << data << std::endl;
}
template<class T>
void write(const T& data)
{
std::cout << "Writing generic: " << data << std::endl;
}
template<class T, class ...U>
void write(T&& obj, U&&... objs)
{
write(std::forward<T>(obj));
write(std::forward<U>(objs)... );
}
int main(int, char**)
{
int j = 0;
write("a", j);
return 0;
}
答案 0 :(得分:1)
这个问题的答案可能有点复杂。我会尝试变得更简单。
看来,在引用折叠后,过载解决方案的候选者为write(const T&)
和write(T&)
,都为T = int
,第二个为U... = (none)
。这样,选择了后者,然后再次调用转发功能。
答案 1 :(得分:1)
除iBug's anwser外,这是一条特殊规则,对于类型为T&
的左值参数,const T&
胜过T
。对于其他情况(const T
,T&
,T
),两个隐式转换序列都是精确匹配项(T -> const T
是资格调整,这也是精确匹配项),因此两者均不胜过另一个,第一个write
比第二个更专业,因此选择第一个。