2012-09-05 4 views
7

それがどのように機能するかを見てみると、のstd::common_typeのlibstdC++の実装を見てきました。私はそれがどのように動作するのか本当に理解していないことを認めなければならない。ここには:std :: common_type implementation

/// common_type 
template<typename... _Tp> 
    struct common_type; 

template<typename _Tp> 
    struct common_type<_Tp> 
    { typedef _Tp type; }; 

template<typename _Tp, typename _Up> 
    struct common_type<_Tp, _Up> 
    { typedef decltype(true ? declval<_Tp>() : declval<_Up>()) type; }; 

template<typename _Tp, typename _Up, typename... _Vp> 
    struct common_type<_Tp, _Up, _Vp...> 
    { 
     typedef typename 
     common_type<typename common_type<_Tp, _Up>::type, _Vp...>::type type; 
    }; 

第1、第2、第4の宣言がどのように機能するのかよくわかります。しかし、私は3番目の宣言の仕組みを理解することはできません。誰かがここで使用されているメカニズムを説明しようと思いますか?

答えて

8

まず、std::declval<T>()Tのr値を返します。値を使って何かをしようとすると失敗するので、評価のつかない状況でしか使用できません。次に、3項演算子は、その型を両方の引数に共通の最も特化した型として推論します(型がない場合は失敗します)。だから、表現

true? declval<T0>(): declval<T1>() 

の種類は、T0T1の最も専門的な一般的なタイプです。残っていることは、この式を型に変換し、評価されていないことを確認することです。 decltype(expr)はこれだけです。明らかに、ロジックのビーフの2つの引数バージョン:コーナーケース(1つの引数)を扱い、2つの引数バージョンを利用して共通タイプの任意の型を生成するものがあります。

3

第3のバージョンでは、条件演算子を使用して共通タイプを判別します。そのルールは、標準のセクション5.16にかなりの長さで記述されているので、私はここでそれらをコピーすべきかどうかはわかりません。

が簡単に言えば、式:そのようなものが存在する場合

boolean-expression ? second-operand : third-operand 

は、第二及び第三のオペランドの「一般的なタイプ」を有します。 decltype指定子は、式を型指定子に「変換する」ために使用されます。

+3

+1、三項演算子を含む*魔法*の読み方:[条件付き愛:FOREACH還元](http://www.artima.com/cppsource/foreach.html) –

+0

トリック。したがって、3項演算子はそのオペランドに基づいて戻り値の型を推定するという事実に依存します。それはそれを考えなかった。ありがとう! – Morwenn

1

Long Story Short:decltypeは、C++コンパイラが最も近い祖先型を決定するようにしています。

3次演算子には、結果として得られる2つの式のうち最も近い祖先の静的型があります。

例えば:

Aは

XはYを継承Bから継承これは、どのようにC++言語作品であるB

<expression> ? <expression with static type A> : <expression with static type X> 
    = <expression with static type B> // this is how the C++ parser sees it 

から継承します。 decltypeはtypedefをその式の結果の静的型にします(C++コンパイラがそれを決定した型)。

+0

これは、* ancestor *という用語の使用や、継承を使用した例では、やや誤解を招くことがあります。もちろん、そのタイプのうちの1つが他のタイプに変換可能であれば、それは第2のタイプを選択します。たとえば '(true?1、1.)'は 'double ' *祖先*や*継承*はありませんが、intはdoubleに変換可能です。 –