4

ユニバーサル参照パラメーターが右辺値参照引数と一致すると、右辺値参照引数が返されると思います。ただし、私のテストでは、ユニバーサル参照関数テンプレートによって右辺値参照が左辺値参照に変換されることが示されています。なぜそうなのですか?

#include <iostream>
#include <type_traits>
using namespace std;
template <typename T>
T f1(T&&t) {  //<-----this is a universal reference
  cout << "is_lvalue reference:" << is_lvalue_reference<T>::value << endl;
  cout << "is_rvalue reference:" << is_rvalue_reference<T>::value << endl;
  cout << "is_reference:"        << is_reference<T>::value        << endl;
  return t;
}
void f2(int&& t) {
  cout << "f2 is_lvalue reference:" << is_lvalue_reference<decltype(t)>::value << endl;
  cout << "f2 is_rvalue reference:" << is_rvalue_reference<decltype(t)>::value << endl;
  cout << "f2 is_reference:" << is_reference<decltype(t)>::value << endl;
  f1(t);

}

int main()
{
  f2(5);
  return 0;
}

GCC と VC++2010 の両方で、これは結果です。

f2 is_lvalue reference:0
f2 is_rvalue reference:1
f2 is_reference:1
is_lvalue reference:1
is_rvalue reference:0
is_reference:1

つまり、 のパラメータtf2右辺値参照でしたが、 に渡されるf1と、パラメータは左辺値参照になりました。の右辺値性を保持すべきではありませんf1か?

4

4 に答える 4

3

を呼び出しf1(t)、引数は式tです。ないstatic_cast<decltype(t)>(t)か何か。の検査はdecltype(t)の呼び出しとは何の関係もありませんf1(t)

tには型intと値のカテゴリlvalueがあります。(経験則では、式のアドレスを取得できる場合、それは左辺値であり、確かに と書くことができます&t)。参照変数が最初に参照として宣言されたという「情報」は、decltype検査を介してのみ表示されます。

f1は左辺値で呼び出されるため、とT推定されint&ます。

注意。で true であることを確認したい場合は、ではなくf1も使用することをお勧めします。右辺値引数の場合、非参照型に推定します。たとえば、do thenのisとin isにすることで修正した場合。decltype(t)Tis_rvalue_referencef1Tf2f1(std::move(t));f1Tintdecltype(t)f1int&&

于 2016-12-28T13:14:43.227 に答える
0

C++11 標準を勉強した後、私のf1(t);in の後に何が起こっていたのか、漠然とした考えを持っていf2ます。ここで説明して、それが正しいかどうかを確認します。

  1. ではf2t型の左辺値ですint&&( ではなくint、これは重要な違いです)
  2. この呼び出しf1(t);により、型は次のように推定されます。

    2.1 Tin にf1左辺値が与えられると、その左辺値の型の参照として推定されるか、int&& &

    2.2 参照の崩壊によりint&& &、 が発生しint &ます。これは の値ですT

  3. のパラメータはf1として宣言されているため、 のパラメータのT&&型は です。そのため、 asの型を推測するために参照の崩壊が 2 回発生します。tf1int & &&tint &

  4. したがって、T=int &であり、パラメータのタイプtは ですint &。つまり、パラメーターtは型の左辺値ですint &

任意のコメント?

于 2016-12-28T14:45:38.740 に答える
-1

std::forward を使用して、t を右辺値として保持します。

void f2(int&& t) {
  //....
  f1(std::forward<int>(t));
}

t 引数は右辺値として渡され、int 型として推定されます。(ここで控除がどのように行われるかを参照してください)

std::forward(t) は int&& 型の右辺値を返すため、 f1(int&&) を呼び出します

std::forward(t) がない場合、f1(t) は int 型の引数を取り、f1(int&) を呼び出します。

更新:の違いに注意してください

 is_lvalue_reference<T> and is_lvalue_reference<decltype<t>>. 

テンプレートでは、T は関数の引数に基づいて推定されますが、t の値カテゴリは常に f2 の左辺値であり、

forward<int>(t) and move(t) 

常に右辺値です。

#include <iostream>
#include <type_traits>

class A {};


template <typename T>
T f0(T& t) {  //<-----this is a universal reference
    std::cout<< "f0 lvalue"<<'\n';

    // take T as template argument, it is type int, so not rvalue, not lvalue.
//  std::cout << "is_lvalue reference:" << std::is_lvalue_reference<T>::value << std::endl;
    std::cout << "is_lvalue reference:" << std::is_lvalue_reference<T>::value << std::endl;
    std::cout << "is_rvalue reference:" << std::is_rvalue_reference<T>::value << std::endl;
    std::cout << "is_reference:"        << std::is_reference<T>::value        << std::endl;
    return t;
}

template <typename T>
T f0(T&&t) {  //<-----this is a universal reference
    std::cout<< "f0 rvalue"<<'\n';
    std::cout << "is_lvalue reference:" << std::is_lvalue_reference<T>::value << std::endl;
    std::cout << "is_rvalue reference:" << std::is_rvalue_reference<T>::value << std::endl;
    std::cout << "is_reference:"        << std::is_reference<T>::value        << std::endl;
    return t;
}

template <typename T>
T f1(T& t) {  //<-----this is a universal reference
    std::cout<< "f1 lvalue"<<'\n';

    // take T as template argument, it is type int, so not rvalue, not lvalue.
//  std::cout << "is_lvalue reference:" << std::is_lvalue_reference<T>::value << std::endl;
    std::cout << "is_lvalue reference:" << std::is_lvalue_reference<decltype(t)>::value << std::endl;
    std::cout << "is_rvalue reference:" << std::is_rvalue_reference<decltype(t)>::value << std::endl;
    std::cout << "is_reference:"        << std::is_reference<decltype(t)>::value        << std::endl;
    return t;
}

template <typename T>
T f1(T&&t) {  //<-----this is a universal reference
    std::cout<< "f1 rvalue"<<'\n';
    std::cout << "is_lvalue reference:" << std::is_lvalue_reference<decltype(t)>::value << std::endl;
    std::cout << "is_rvalue reference:" << std::is_rvalue_reference<decltype(t)>::value << std::endl;
    std::cout << "is_reference:"        << std::is_reference<decltype(t)>::value        << std::endl;
    return t;
}

void f2(int&&t) {  //<-----this is a universal reference
    std::cout<< "f2 rvalue"<<'\n';
    std::cout << "is_lvalue reference:" << std::is_lvalue_reference<decltype(t)>::value << std::endl;
    std::cout << "is_rvalue reference:" << std::is_rvalue_reference<decltype(t)>::value << std::endl;
    std::cout << "is_reference:"        << std::is_reference<decltype(t)>::value        << std::endl;


    f1(std::forward<int>(t));   // T is deduced as int for f(T&&), type int is not rvalue, nor lvalue, t is rvalue
    f1(std::move(t));           // T is deduced as int for f(T&&), type int is not rvalue, nor lvalue, t is rvalue
    f1(t);                      // T is deduced as int for f(T&),  type int is not rvalue, nor lvalue, t is lvalue
                                //if f1(T&) not exist, then f1(t) will call f1(T&&), T is deduced as int&, type int& is lvalue, t is lvalue


    f0(std::forward<int>(t));   // T is deduced as int for f(T&&), type int is not rvalue, nor lvalue, t is rvalue
    f0(std::move(t));           // T is deduced as int for f(T&&), type int is not rvalue, nor lvalue, t is rvalue
    f0(t);                      // T is deduced as int for f(T&),  type int is not rvalue, nor lvalue, t is lvalue
                                //if f0(T&) not exist, then f0(t) will call f0(T&&), T is deduced as int&, type int& is lvalue, t is lvalue
}




void test_rvalue()
{

    f2(5);
    std::cout << std::boolalpha;
    std::cout << std::is_lvalue_reference<A>::value << '\n';        // A is not lvalue
    std::cout << std::is_rvalue_reference<A>::value << '\n';        // A is not rvalue
    std::cout << std::is_lvalue_reference<A&>::value << '\n';       // A& is lvalue
    std::cout << std::is_rvalue_reference<A&&>::value << '\n';      // A&& is rvalue
    std::cout << std::is_lvalue_reference<int>::value << '\n';      // int is not lvalue
    std::cout << std::is_rvalue_reference<int>::value << '\n';      // int is not rvalue
    std::cout << std::is_lvalue_reference<int&>::value << '\n';     // int& is lvalue
    std::cout << std::is_rvalue_reference<int&&>::value << '\n';    // int&& is rvalue

}
于 2021-01-17T12:40:33.987 に答える