如果我通过通用引用接受参数,那么 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?

此代码是否可能打印 "neither"?

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 it ever possible for this code to print "neither"?

是的。

foo(5); // neither

If I accept a parameter via universal reference, is exactly one of is_rvalue_reference and is_lvalue_reference true?

参数 t 将具有右值引用类型或左值引用类型。另一方面,类型 T 将根据推导和 reference collapsing 规则而有所不同。相反,如果您将 is_lvalue/rvalue_reference<T> 更改为 is_lvalue/rvalue_reference<decltype(t)>,则永远不会执行 else 路径。

Is it ever possible for this code to print "neither"?

是的,只要将右值传递给 foo 且未给出显式模板参数,就会打印 "neither":

foo(42);  // "neither" is printed because T is deduced as int

或者当明确指定 non-reference 类型时:

int i=0;
// "neither" is printed because T is explicitly specified as int:
foo<int>(std::move(i));

虽然 T 可以是 non-reference 类型,但 t 的类型将始终是引用类型。 t的类型有三种可能:

  1. T是值类型(即int):t的类型是int&&; rvalue-reference 到 int.
  2. T是一个lvalue-reference(即int&):t的类型是int& &&,折叠成int&; lvalue-reference 到 int.
  3. T是一个rvalue-reference(即int&&):t的类型是int&& &&,折叠成int&&; rvalue-reference 到 int.

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

Is it ever possible for this code to print "neither"?

是的。根据forwarding reference的类型推导规则,当传递左值时,T将推导为lvalue-reference类型,当传递右值时,将推导T作为 non-reference 类型。例如

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

LIVE

另一方面,除非明确指定模板参数,否则不会打印 "rv"

另一方面(再次),如果您检查函数参数的类型 t,它将是 lvalue-reference 类型或 rvalue-reference 类型; "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