2016-09-28 1 views
3

私はtie pre C++ 11の動作を模倣しようとしています。make_pairを使って結び付けることができないのはなぜですか?

pair<int, int> test() { 
    return make_pair(13, 42); 
} 

int main() { 
    int a = 1, b = 2; 

    pair<int&, int&>(a, b) = test(); 

    cout << a << ' ' << b << endl; 
} 

This works私はpairコンストラクタabに代わりmake_pairを使用する場合が割り当てられていません。
pairコンストラクタは動作しますが、make_pairでは動作しないのはなぜですか?

答えて

3

[lib.pairs] 8 pairは、 "明示的なタイプ" make_pairさんしばらく「タイプを使用していることを、標準状態推論される "。

これは、標準がpairのコンストラクタを定義する理由は次のとおりです。

template <class T1, class T2> 
pair(const T1& x, const T2& y) 

あなたがC++03 compilerにあなたのコードを実行する場合は、このエラーメッセージが表示されます:

non-static reference member int& std::pair<int&, int&>::first , can't use default assignment operator

問題はpairが使用していることですimplicitly-declared copy assignment operatorこれが定義されていない場合は、pair

Has a non-static data member of a reference type

make_pairまたはpairコンストラクタで定義されているテンプレート引数は、pairのメンバの両方をint&と定義するため、暗黙的に宣言されたコピー代入演算子は定義されません。 これはC++ 03のpairでは実現できません。

リターン・パラメータを使用することが望ましくない場合、あなたはtieの独自の実装を書くことができますが:

tie<int, int>(a, b) = test(); 

正確なCを取得するには++:

template <class T1, class T2> 
struct tie{ 
    T1& first; 
    T2& second; 

    tie(T1& x, T2& y) : first(x), second(y) {} 

    tie<T1, T2>& operator=(const pair<T1, T2>& rhs){ 
     first = rhs.first; 
     second = rhs.second; 

     return *this; 
    } 
}; 

これはpairの割り当てができるようになりますテンプレート引数を必要としない11の振る舞いでは、関数を定義する必要があります。これは、単にC++ 11とpairの割り当てを可能にする

template <class T1, class T2> 
details::tie<T1, T2> tie(T1& x, T2& y) { 
    return details::tie<T1, T2>(x, y); 
} 

tienamespace detailsにネストされている場合、関数は次のように定義することができる

tie(a, b) = test(); 

Live Example

なおこれはまだint&テンプレート引数を使用することを許容しないので、details::tie<int&, int&>tie<int&, int&>は以前と同じように失敗します。

2

make_pairは、参照ではなく1対の値を生成します。つまり、あなたの例ではpair<int, int>が生成され、test()という結果を一時変数に割り当てることになります。

あなたは以下でtieを模倣することができます。

template<typename T, typename U> 
std::pair<T&, U&> tie_pair(T& l, U& r) 
{ 
    return std::pair<T&, U&>(l, r); 
} 

http://ideone.com/muAcaG

が、これはC++ 03は、REF-修飾子を持っていないの不幸な副作用です¹しました。 C++ 11以上では、this(非標準クラス)のoperator=を削除して、そのようなケースを静かな驚くべき動作ではなくコンパイラエラーにすることができます。

+0

私はこれを行うことによってあなたが言っていることを検証しました。 'pair foo = make_pair (a、b)'エラー: "' std :: pair 'から非スカラー型' std :: pair 'への変換が要求されています。これがなぜなのか、もう少し詳しく教えてください。 'make_pair'が参照型を取り除くだけの場合、なぜそれらをテンプレート引数として渡すことができますか? –

+1

あなたは 'make_pair'にテンプレートパラメータを提供するつもりはありません。あなたができることは、言語セマンティクスの単なる(この場合は不幸な)効果です。なぜなら、*なぜ*が行くかは、参照ではなくスタンドアロンの値を作るように設計されたからです。私は具体的な実装についてはわかりませんし、C++ 2003の標準を持っていない方が良いでしょう – krzaq

3

実際にはstd::make_pairを使用できます。しかし、参照を模倣するにはreference_wrapperクラスを実装する必要があります。 (として期待される非常に洗練ませんが、作業)Examplary C++ 03のアプローチ:20.2.2で

#include <iostream> 
#include <utility> 

using namespace std; 

template <class T> 
struct reference_wrapper { 
    bool is_const; 
    T* v; 
    T const* cv; 
    reference_wrapper(T& t): v(&t), is_const(false) { } 
    reference_wrapper(T const& t): cv(&t), is_const(true) { } 

    reference_wrapper &operator=(reference_wrapper const &rw) { 
     if (rw.is_const) { 
     *v = *rw.cv; 
     } else { 
     *v = *rw.v; 
     } 
    } 
}; 

template <class T> 
reference_wrapper<T> ref(T &t) { 
    return reference_wrapper<T>(t); 
} 

pair<int, int> test() { 
    return make_pair(13, 42); 
} 

int main() { 
    int a = 1, b = 2; 

    //pair<int&, int&>(a, b) = test(); // works 
    make_pair(ref(a), ref(b)) = test(); // now it does work 

    std::cout << a << ' ' << b << std::endl; 
} 
+0

@krzaq本当にありません:)ありがとうございます編集... –

+3

私はこの答えが私のものより良いのですが、 'std :: ref'はC++ 11以降でのみ利用可能です – krzaq

+1

@krzaq私はそれを言うつもりでした! 'ref'を使っているなら、' tie'を使う方が良いでしょう。 –

関連する問題