web-dev-qa-db-ja.com

std :: decayとは何ですか?

std::decay が存在する理由は何ですか? std::decay はどのような状況で役立ちますか?

<joke>放射性std::atomicタイプを非放射性タイプに分解するために明らかに使用されます。</ joke>

N2609 は、std::decayを提案した論文です。論文では次のように説明しています。

簡単に言えば、decay<T>::typeは、Tが配列型または関数型への参照である場合を除き、ID型変換です。これらの場合、decay<T>::typeはそれぞれ、ポインターまたは関数へのポインターを生成します。

動機付けの例はC++ 03 std::make_pairです。

template <class T1, class T2> 
inline pair<T1,T2> make_pair(T1 x, T2 y)
{ 
    return pair<T1,T2>(x, y); 
}

文字列リテラルを機能させるために、値でパラメータを受け入れました:

std::pair<std::string, int> p = make_pair("foo", 0);

参照によってパラメータを受け入れた場合、T1は配列型として推定され、pair<T1, T2>の構築は不正な形式になります。

しかし、明らかにこれは重大な非効率につながります。したがって、値渡しが発生したときに発生する一連の変換を適用するためのdecayの必要性により、参照によってパラメーターを取得する効率を得ることができますが、コードに必要な型変換を取得することもできます文字列リテラル、配列型、関数型などを操作します。

template <class T1, class T2> 
inline pair< typename decay<T1>::type, typename decay<T2>::type > 
make_pair(T1&& x, T2&& y)
{ 
    return pair< typename decay<T1>::type, 
                 typename decay<T2>::type >(std::forward<T1>(x), 
                                            std::forward<T2>(y)); 
}

注:これは実際のC++ 11 make_pair実装ではありません-C++ 11 make_pairも展開std::reference_wrappers。

159
T.C.

テンプレートタイプのパラメータを取るテンプレート関数を扱う場合、多くの場合、ユニバーサルパラメータがあります。ユニバーサルパラメーターは、ほとんどの場合、何らかの種類の参照です。また、それらはconst-volatile認定済みです。そのため、ほとんどの型特性は期待どおりに機能しません。

template<class T>
void func(T&& param) {
    if (std::is_same<T,int>::value) 
        std::cout << "param is an int\n";
    else 
        std::cout << "param is not an int\n";
}

int main() {
    int three = 3;
    func(three);  //prints "param is not an int"!!!!
}

http://coliru.stacked-crooked.com/a/24476e60bd906bed

ここでの解決策は、std::decayを使用することです。

template<class T>
void func(T&& param) {
    if (std::is_same<typename std::decay<T>::type,int>::value) 
        std::cout << "param is an int\n";
    else 
        std::cout << "param is not an int\n";
}

http://coliru.stacked-crooked.com/a/8cbd0119a28a18bd

55
Mooing Duck