如果我通过通用引用接受参数,则is_rvalue_reference和is_lvalue_reference之一是否正确?

时间:2019-07-12 00:19:15

标签: c++ c++17 rvalue-reference rvalue lvalue

此代码是否有可能打印“都不”?

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;
    }
}

3 个答案:

答案 0 :(得分:3)

  

此代码是否有可能打印“都不”?

是的,只要将右值传递给foo并且没有给出明确的模板参数,就不会打印“都不”:

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的类型有三种可能性:

  1. T是一个值类型(即int):t的类型为int&&;对int的右值引用。
  2. T是左值引用(即int&):t的类型为int& &&,折叠为int&;对int的左值引用。
  3. T是右值引用(即int&&):t的类型为int&& &&,折叠为int&&;对int的右值引用。

这是转发引用工作的机制。如果将右值传递给foo,则将推论T为值类型。如果传递左值,则将推论T是左值引用类型。

答案 1 :(得分:2)

  

此代码是否有可能打印“都不”?

是的

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路径将永远无法执行。

答案 2 :(得分:1)

  

此代码是否有可能打印“都不”?

是的。根据{{​​3}}的类型推导规则,当传递左值时,T将推导左值引用类型,当传递右值时,T将推导为非引用类型。例如

int i;
foo(i); // T is deduced as int&
foo(0); // T is deduced as int

forwarding reference

另一方面,除非明确指定模板参数,否则不会打印"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