将左值传递给 RValue 的参数

问题描述 投票:0回答:2

我想知道这怎么可能?

template<typename T>
void Test(T&& arg)
{
    arg = 14;
}


int a = 23;
Test(a);

我的问题是函数 Test 需要一个右值类型的参数,但是它似乎也接受左值类型的参数。这是为什么 ?那是因为模板的存在吗?因为如果我做这样的事情

void AnotherTest(int&& arg)
{
    arg = 14;
}

然后函数要求参数是右值类型。 如果有人能解释为什么模板的存在会改变行为,我将不胜感激。

c++ templates rvalue-reference
2个回答
5
投票

正如您正确想象的那样,关键是它是一个模板参数类型被推导。当您使用左值调用

Test
时,参数类型推导规则 当参数是右值引用 时,会将类型
T
推断为 lvalue-reference,因此特化变为:

template <>
void Test<int&>(int & && arg)

此时引用折叠规则开始生效,参数类型变为:

template <>
void Test<int&>(int & arg)

虽然模板采用 rvalue-reference,如果类型是 lvalue-reference 参数本身就变成了 lvalue-reference


0
投票

那是因为模板的存在吗?

有点,但严格来说不是。更准确地说,出现此行为是因为您有一个引用类型的别名。模板参数是您最有可能看到的场景,但您可以在没有模板的情况下合成行为。

using T = int&; // Alias, not a template parameter

void AnotherTest(T&& arg)
{
    arg = 14;
}

我没有使用模板参数作为别名,而是使用了

using
关键字(
typedef
也可以)。就像在您的模板设置中一样,对左值引用的右值引用折叠到左值引用。也就是说,
T&&
在这种情况下与
T
相同。所以你可以调用
AnotherTest(a)
并让
arg
绑定到
a
.


另一方面,您可以保留模板并仍然复制错误。关键是要指定模板参数,而不是让它被推导。

    Test<int>(a);

 error: cannot bind rvalue reference of type 'int&&' to lvalue of type 'int'

上面的要点是你可能误解了编译器将你的模板参数推断为什么。当您调用

Test(a)
时,您可能认为
T
int
,但是您的编译器(对此事有最终决定权)决定
T
int&

© www.soinside.com 2019 - 2024. All rights reserved.