具有引用折叠的函数模板重载
Function template overloading with reference collapsing
除了这个问题,,我还有一个问题。请注意,您不必阅读此 post 即可理解这一点,但这可能会有所帮助。 post 顺便说一句,我认为没有显示出问题的理想解决方案,但这不是重点。
template <typename Buf>
void copy (
Buf&& input_buffer,
Buf& output_buffer)
{} // 1)
template <typename Buf>
void copy (
Buf& input_buffer,
Buf& output_buffer)
{} // 2)
...
int i = 4;
int j = 6;
copy<int&>(i, j); // copy taking two l-values; calls second instance.
我希望如果我调用 copy<int&>(i,j)
,将调用 copy
的第一个实例。类型 Buf
已指定,因此不需要推导。 Reference collision rules
导致 input_buffer
和 output_buffer
都是左值引用。第一个实例是第一个有效函数。
它不是模板特化,所以令我惊讶的是,编译器实际上选择了其中一个,而不是给出错误。
copy
的第二个实例可能看起来更具体,但如果 Buf
是 int&
,第一个实例也需要两个左值引用。
那么,问题来了,为什么首选二审呢?我希望编译器首先通过替换模板参数实际创建函数。然后,事实证明实例一中的 Buf&& input_buffer
等于 Buf&
.
欢迎询问我是否需要详细说明。
模板(1)和(2)都实例化为相同的签名,因此调用哪个取决于偏序规则。部分排序对模板声明进行操作,而不是对隐式实例化产生的特化进行操作,也不对其显式特化进行操作。
根据偏序规则,我们判断(1)是否至少和(2)一样通用,以及(2)是否至少和(1)一样通用。如果答案分别是"yes"和"no",则(2)更专业,因此被选中。
为了确定 (1) 是否至少与 (2) 一样通用,我们为 Buf
合成了一些独特的类型并将其代入 (2) 的签名中,然后尝试推导 (2) 的参数(1) 由如此生成的假设专业化。这个想法是,如果这适用于唯一类型,那么它也必须适用于所有其他类型。
的确,如果我们在 (2) 中代入 Buf
= Unique
,我们得到
void copy (Unique& input_buffer, Unique& output_buffer)
这导致 Buf
在 (1) 中被推导为 Unique&
(这是有效的,因为引用折叠规则)。
如果我们反过来做,将 Buf = Unique
代入 (1),这将导致签名
void copy (Unique&& input_buffer, Unique& output_buffer)
现在我们尝试从中推导出 (2) 中的 Buf
——但当然它不起作用,因为 (2) 只能生成两个参数都是左值引用的特化。
除了这个问题,
template <typename Buf>
void copy (
Buf&& input_buffer,
Buf& output_buffer)
{} // 1)
template <typename Buf>
void copy (
Buf& input_buffer,
Buf& output_buffer)
{} // 2)
...
int i = 4;
int j = 6;
copy<int&>(i, j); // copy taking two l-values; calls second instance.
我希望如果我调用 copy<int&>(i,j)
,将调用 copy
的第一个实例。类型 Buf
已指定,因此不需要推导。 Reference collision rules
导致 input_buffer
和 output_buffer
都是左值引用。第一个实例是第一个有效函数。
它不是模板特化,所以令我惊讶的是,编译器实际上选择了其中一个,而不是给出错误。
copy
的第二个实例可能看起来更具体,但如果 Buf
是 int&
,第一个实例也需要两个左值引用。
那么,问题来了,为什么首选二审呢?我希望编译器首先通过替换模板参数实际创建函数。然后,事实证明实例一中的 Buf&& input_buffer
等于 Buf&
.
欢迎询问我是否需要详细说明。
模板(1)和(2)都实例化为相同的签名,因此调用哪个取决于偏序规则。部分排序对模板声明进行操作,而不是对隐式实例化产生的特化进行操作,也不对其显式特化进行操作。
根据偏序规则,我们判断(1)是否至少和(2)一样通用,以及(2)是否至少和(1)一样通用。如果答案分别是"yes"和"no",则(2)更专业,因此被选中。
为了确定 (1) 是否至少与 (2) 一样通用,我们为 Buf
合成了一些独特的类型并将其代入 (2) 的签名中,然后尝试推导 (2) 的参数(1) 由如此生成的假设专业化。这个想法是,如果这适用于唯一类型,那么它也必须适用于所有其他类型。
的确,如果我们在 (2) 中代入 Buf
= Unique
,我们得到
void copy (Unique& input_buffer, Unique& output_buffer)
这导致 Buf
在 (1) 中被推导为 Unique&
(这是有效的,因为引用折叠规则)。
如果我们反过来做,将 Buf = Unique
代入 (1),这将导致签名
void copy (Unique&& input_buffer, Unique& output_buffer)
现在我们尝试从中推导出 (2) 中的 Buf
——但当然它不起作用,因为 (2) 只能生成两个参数都是左值引用的特化。