功能模板重载而参考折叠

时间:2018-11-06 19:19:37

标签: c++ c++11 templates overloading function-templates

除了这个问题Function template deduction l-value reference and universal reference,我还有另一个问题。请注意,您不必阅读本文即可了解这一点,但这可能会有所帮助。顺便说一下,这篇文章并没有显示出我所认为的问题的理想解决方案,但这并不是重点。

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_bufferoutput_buffer均为左值引用。第一个实例是第一个有效函数。

这不是模板专门化,因此让编译器实际上选择其中一种而不是给出错误也令我感到惊讶。

copy的第二个实例可能看起来更具体,但是如果Bufint&,则第一个实例还需要两个l值引用。

所以,问题是,为什么首选第二实例?我希望编译器首先通过替换模板参数来实际创建函数。然后,事实证明实例1中的Buf&& input_buffer等于Buf&

随时问我是否需要详细说明。

1 个答案:

答案 0 :(得分:4)

模板(1)和(2)都实例化为相同的签名,因此调用哪个签名取决于部分排序规则。局部排序对模板声明起作用,而不是对隐式实例化产生的特化或显式特化进行操作。

根据偏序规则,我们确定(1)是否至少与(2)一般,以及(2)是否至少与(1)一般。如果答案分别是“是”和“否”,则选择(2)更专业。

要确定(1)是否至少与(2)通用,我们为Buf合成一个唯一类型并将其替换为(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)只能生成两个参数均为左值引用的特殊化。