web-dev-qa-db-ja.com

std :: remove_referenceについて説明しましたか?

以下のように std::remove_reference の可能な実装を見ました

template< class T > struct remove_reference      {typedef T type;};
template< class T > struct remove_reference<T&>  {typedef T type;};
template< class T > struct remove_reference<T&&> {typedef T type;};   

lvaluervalue referenceの特殊化があるのはなぜですか?一般的なテンプレート自体で十分ではなく、参照を削除しませんか? T&またはT&&専門分野で::typeを使用しようとすると、T&またはT&&をそれぞれ正しく取得する必要があるため、ここで混乱しています。

移動中にremove_reference<t>::type&&にキャストする理由を説明していただけますか? (パラメーターに名前が付けられているため、移動関数内で左辺値として扱われるからですか?).

また、タイプが何であるかを見つけて印刷できる方法を教えていただけますか?たとえば、タイプrvalueintの場合、int&&が渡されたことを出力できるはずですか? (私はstd::is_sameを使用してチェックしていますが、手動で行っています。)

お時間をいただきありがとうございます。

36
Koushik Shetty

なぜ左辺値と右辺値の参照に特化があるのですか?

プライマリテンプレートのみが存在する場合は、次のようにします。

_remove_reference<int&>::type
_

あなたに与えるでしょう:

_int&
_

そしてやって:

_remove_reference<int&&>::type
_

あなたに与えるでしょう:

_int&&
_

それはあなたが望むものではありません。左辺値参照と右辺値参照の特殊化により、渡す型引数からそれぞれ_&_と_&&_を取り除くことができます。

たとえば、あなたがしている場合:

_remove_reference<int&&>
_

タイプ_int&&_は、_T&&_特殊化で指定されたパターンに一致します。Tintです。特殊化により、型エイリアスtypeT(この場合はint)であると定義されているため、次のようにします。

_remove_reference<int&&>::type
_

intを提供します。

moveで_remove_reference<t>::type&&_にキャストする理由と方法を説明できますか?

これは、move()が次のように定義されているためです。

_    template<typename T>
    T&& move(T&& t) { ... }
//  ^^^
//  Resolves to X& if T is X& (which is the case if the input has type X
//  and is an lvalue)
_

次に、move()の引数がX型の左辺値である場合、戻り値の型は_X&_になります(いわゆる「ユニバーサル参照」)。戻り値の型がalways右辺値参照であることを確認します。

move()の目的は、入力で何を渡しても、右辺値を返すことです。戻り値の型が右辺値参照である関数の関数呼び出しは右辺値であるため、move()が常に右辺値参照を返すようにする必要があります。

_remove_reference<T>::type&&_を非参照型に追加すると常に右辺値参照型が生成されることが保証されるため、これが_&&_を実行する理由です。

また、タイプを見つけて出力する方法を教えていただけますか?

ここでの「印刷」の意味がわかりません。型の名前を文字列に変換する方法を知っている移植可能な方法はありません(その型を取得する方法に関係なく)。

一方、右辺値が渡されたことを確認することが目的の場合は、次のような静的アサーションを使用できます。

_#include <type_traits>

template<typename T>
void foo(T&&)
{
    static_assert(!std::is_reference<T>::value, "Error: lvalue was passed!");
    // ...
}
_

これは、型Xの左辺値が渡されるときに、Tが_X&_であると推定されるという事実に依存しています。

置換の失敗のみを生成する場合は、同等のSFINAE制約を使用することもできます。

_#include <type_traits>

template<typename T, typename std::enable_if<
    !std::is_reference<T>::value>::type* = nullptr>
void foo(T&&)
{
    // ...
}
_
41
Andy Prowl

一部のタイプをテンプレートパラメータとして扱う場合、コンパイラは最も「特殊化された」特殊化を検索します。このテンプレートにint &&を渡すと、コンパイラは_remove_reference<T&&>_バージョンを使用します。一般的な特殊化はあなたが望むものを与えません-一般的な特殊化に_int&&_を渡すと、型は_int&&_になります

タイプを印刷する場合は、typeid(some_type).name()を使用します

0
Evgeny Eltishev