web-dev-qa-db-ja.com

std ::参照のペア

std::pairの参照を持つことは有効ですか?特に、代入演算子に問題はありますか? このリンク によると、operator =による特別な処理はないようであるため、デフォルトの割り当て演算子を生成することはできません。

pair<T&, U&>があり、それに(値または参照の)別のペアを割り当てて、ポイントされたオブジェクトを変更できるようにしたいと思います。

33
Alexandre C.

いいえ、C++ 03ではできませんpairのコンストラクターはTへの参照を取得するためです。 、および 参照への参照は無効です をC++ 03で作成します。

「確実に」と言ったことに注意してください。まだ使用されているいくつかの一般的なコンパイラ(GCCの場合、GCC4.1をテストしました。 @ Charles 報告されたGCC4.4.4)は、参照への参照の形成を許可していませんが、最近では doは、参照の折りたたみを実装するときに許可します(Tが参照型の場合はT&Tです)。あなたのコードがそのようなものを使用している場合、それを試して見るまで、他のコンパイラで動作することを信頼することはできません。

boost::Tuple<>を使いたいようですね

int a, b;

// on the fly
boost::tie(a, b) = std::make_pair(1, 2);

// as variable
boost::Tuple<int&, int&> t = boost::tie(a, b);
t.get<0>() = 1;
t.get<1>() = 2;

C++ 11では、std::pair<std::reference_wrapper<T>, std::reference_wrapper<U>>を使用でき、そのタイプのオブジェクトは希望どおりに動作します。

24
user283145

std::pairの住宅参照を持つことは合法だと思います。 std::mapstd::pairconst型で使用しますが、どちらにも割り当てることはできません。

pair<T&, U&>が欲しいのですが、それに別のペアを割り当てることができます

参照をリセットできないため、割り当ては機能しません。ただし、そのようなオブジェクトをコピー初期化することはできます。

7
sbi

私はあなたと同じように考えていたと思います。私はこの特定のかゆみを掻くために次のクラスを書きました:

template <class T1, class T2> struct refpair{
    T1& first;
    T2& second;
    refpair(T1& x, T2& y) : first(x), second(y) {}
    template <class U, class V>
        refpair<T1,T2>& operator=(const std::pair<U,V> &p){
            first=p.first;
            second=p.second;
            return *this;
        }
};

それはあなたが次のような恐ろしいことをすることを可能にします:

int main (){

    int k,v;
    refpair<int,int> p(k,v);

    std::map<int,int>m;
    m[20]=100;
    m[40]=1000;
    m[60]=3;

    BOOST_FOREACH(p,m){
        std::cout << "k, v = " << k << ", " << v << std::endl;      
    }
    return 0;
}

(関連するインクルードを覚えておいてください)。

もちろん、私が割り当てているkvへの参照がpの中に隠されているのは厄介です。あなたがこのようなことをすると、それはほとんど再びきれいになります:

template <class T1,class T2>
refpair<T1,T2> make_refpair (T1& x, T2& y){
    return ( refpair<T1,T2>(x,y) );
}

これにより、次のようにループできます。

BOOST_FOREACH(make_refpair(k,v),m){
    std::cout << "k, v = " << k << ", " << v << std::endl;      
}

(私は決してc ++の専門家ではないので、すべてのコメントを歓迎します。)

2
MrMasterplan

あなたが正しいです。参照のペアを作成することはできますが、operator =は使用できなくなります。

2
ybungalobill

C++ 03のstd::pairで何が「間違っている」のかわかりませんが、単純に再実装すれば、問題はありません(同じコンパイラgccclang)。

double a = 1.;
double b = 2.;
my::pair<double, double> p1(5., 6.);
my::pair<double&, double&> p2(a, b);
p2 = p1; // a == 5.

したがって、回避策は、(1)pairを(別の名前空間で)再実装するか、(2)std::pair<T&, T&>に特化するか、(3)単にC++ 11を使用する(refsのstd::pairはボックス)

(1)これは素朴な実装です

namespace my{
template<class T1, class T2>
struct pair{
    typedef T1 first_type;
    typedef T2 second_type;
    T1 first;
    T2 second;
    pair(T1 const& t1, T2 const& t2) : first(t1), second(t2){}
    template<class U1, class U2> pair(pair<U1, U2> const& p) : first(p.first), second(p.second){}
    template<class U1, class U2> 
    pair& operator=(const pair<U1, U2>& p){
      first = p.first;
      second = p.second;
      return *this;
    }
};
template<class T1, class T2>
pair<T1, T2> make_pair(T1 t1, T2 t2){
    return pair<T1, T2>(t1, t2);
}
}

(2)そしてここにstd::pairの特殊化があります(私がstd名前空間のオーバーロード/特殊化をいじっていると不満を言う人もいるかもしれませんが、クラスの機能を拡張することであれば問題ないと思います)

namespace std{
    template<class T1, class T2>
    struct pair<T1&, T2&>{
        typedef T1& first_type;    /// @c first_type is the first bound type
        typedef T2& second_type;   /// @c second_type is the second bound type
        first_type first;
        second_type second;
        pair(T1& t1, T2& t2) : first(t1), second(t2){}
        template<class U1, class U2> pair(pair<U1, U2> const& p) : first(p.first), second(p.second){}
        template<class U1, class U2> 
        pair& operator=(const pair<U1, U2>& p){
          first = p.first;
          second = p.second;
          return *this;
        }
    };
}

明らかな何かが欠けているかもしれません。明らかな欠陥が指摘された場合は、回答を編集できます。

1
alfC