如果我通过通用引用接受参数,is_rvalue_reference 和 is_lvalue_reference 中的一个是不是为真?
Posted
技术标签:
【中文标题】如果我通过通用引用接受参数,is_rvalue_reference 和 is_lvalue_reference 中的一个是不是为真?【英文标题】:If I accept a parameter via universal reference, is exactly one of is_rvalue_reference and is_lvalue_reference true?如果我通过通用引用接受参数,is_rvalue_reference 和 is_lvalue_reference 中的一个是否为真? 【发布时间】:2019-07-12 00:19:15 【问题描述】:这段代码有没有可能打印“nether”?
using namespace std;
template<typename T>
void foo(T&& t)
if constexpr (is_lvalue_reference_v<T>)
cout << "lv" << endl;
else if constexpr (is_rvalue_reference_v<T>)
cout << "rv" << endl;
else
cout <<"neither" << endl;
【问题讨论】:
另一方面,is_lvalue_reference_v<T&&>
和 is_rvalue_reference_v<T&&>
中的一个为真。 @songyuanyao 哎呀,对不起。
@L.F.美好的。我明白你的意思了。
【参考方案1】:
这段代码有没有可能打印“nether”?
是的,任何时候将右值传递给foo
并且没有给出明确的模板参数时,都不会打印“neither”:
foo(42); // "neither" is printed because T is deduced as int
或者当显式指定非引用类型时:
int i=0;
// "neither" is printed because T is explicitly specified as int:
foo<int>(std::move(i));
虽然T
可以是非引用类型,但t
的类型将始终是引用类型。 t
的类型有三种可能:
T
是一个值类型(即int
):t
的类型是int&&
;对int
的右值引用。
T
是一个左值引用(即int&
):t
的类型是int& &&
,它折叠成int&
;对int
的左值引用。
T
是一个右值引用(即int&&
):t
的类型是int&& &&
,它折叠成int&&
;对int
的右值引用。
这是转发引用的工作机制。如果将右值传递给foo
,则T
将被推导出为值类型。如果你传递一个左值,那么T
将被推断为一个左值引用类型。
【讨论】:
很好的答案,但我想您要注意foo<int>(i)
将无法编译(因此它不会打印任何内容)。传递std::move(i)
即可解决。
@JohannesSchaub-litb 嘿,它最初有std::move
,但我虽然“让我们让它显式参数与推断的参数不同”并打破它。加回来了。【参考方案2】:
这段代码有没有可能打印“nether”?
是的。
foo(5); // neither
如果我通过通用引用接受参数,is_rvalue_reference 和 is_lvalue_reference 中的一个是否为真?
参数t
将具有右值引用类型或左值引用类型。另一方面,T
的类型将根据扣除和reference collapsing 规则而有所不同。如果改为将 is_lvalue/rvalue_reference<T>
更改为 is_lvalue/rvalue_reference<decltype(t)>
,则永远无法执行 else 路径。
【讨论】:
【参考方案3】:这段代码有没有可能打印“nether”?
是的。根据forwarding reference的类型推导规则,T
在被传递左值时,会被推导出为左值引用类型,T
被传入右值时,被推导出为非引用类型。例如
int i;
foo(i); // T is deduced as int&
foo(0); // T is deduced as int
LIVE
另一方面,"rv"
不会被打印,除非明确指定模板参数。
另一方面(再次),如果您检查函数参数t
的类型,它将是左值引用类型或右值引用类型; "neither"
不会被打印出来。
int i;
foo(i); // T is deduced as int&, the type of t is int& (int& && -> int&)
foo(0); // T is deduced as int, the type of t is int&&
foo<int&&>(0); // T is specified as int&&, the type of t is int&& (int&& && -> int&&)
LIVE
【讨论】:
以上是关于如果我通过通用引用接受参数,is_rvalue_reference 和 is_lvalue_reference 中的一个是不是为真?的主要内容,如果未能解决你的问题,请参考以下文章