使用参数包和通用参考进行过载选择
Overload selection with parameter pack and universal references
我一直在尝试将完美转发与我递归解压的参数包一起使用,这让我意识到我并不真正理解在存在通用参考。
我的困惑是由类似于以下的一些代码引起的:
#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;
}
这个问题的答案可能有点复杂。我会尽量简单一点。
看起来,在引用合并之后,重载决议的候选者是 write(const T&)
和 write(T&)
,两者都 T = int
,第二个有 U... = (none)
。这样后一个被pick出来,转发函数又被调用了
除了之外,对于T
类型的左值参数,T&
胜过const T&
是一个特殊规则。对于其他情况(const T
、T&
、T
),这两个隐式转换序列都是精确匹配(T -> const T
是限定调整,也是精确匹配)因此都没有超过other,第一个write
比第二个更专业,所以选择第一个。
我一直在尝试将完美转发与我递归解压的参数包一起使用,这让我意识到我并不真正理解在存在通用参考。
我的困惑是由类似于以下的一些代码引起的:
#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;
}
这个问题的答案可能有点复杂。我会尽量简单一点。
看起来,在引用合并之后,重载决议的候选者是 write(const T&)
和 write(T&)
,两者都 T = int
,第二个有 U... = (none)
。这样后一个被pick出来,转发函数又被调用了
除了T
类型的左值参数,T&
胜过const T&
是一个特殊规则。对于其他情况(const T
、T&
、T
),这两个隐式转换序列都是精确匹配(T -> const T
是限定调整,也是精确匹配)因此都没有超过other,第一个write
比第二个更专业,所以选择第一个。