Подтвердить что ты не робот

Std:: пара ссылок

Допустимо ли иметь std::pair ссылок? В частности, существуют ли проблемы с оператором присваивания? В соответствии с эта ссылка, похоже, нет специального обращения с оператором =, поэтому оператор присваивания по умолчанию не сможет быть сгенерирован.

Я хотел бы иметь pair<T&, U&> и иметь возможность назначить ему другую пару (значений или ссылок) и изменить объекты с указаными объектами.

4b9b3361

Ответ 1

Нет, вы не можете сделать это надежно в С++ 03, потому что конструктор pair принимает ссылки на T и создает ссылка на ссылку не является законной в С++ 03.

Обратите внимание, что я сказал "надежно". Некоторые распространенные компиляторы все еще используются (для GCC, я тестировал GCC4.1, @Charles, сообщенный GCC4.4.4), не позволяют формировать ссылку на ссылку, но совсем недавно разрешите это, когда они реализуют сведение ссылок (T& is 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;

Ответ 2

В С++ 11 вы можете использовать std::pair< std::reference_wrapper <T>, std::reference_wrapper<U>>, и объекты этого типа будут вести себя точно так, как вы хотите.

Ответ 3

Я думаю, что было бы законно иметь ссылки на жилье std::pair. std::map использует std::pair с типом const, в конце концов, который не может быть назначен.

Я хотел бы иметь pair<T&, U&> и иметь возможность назначить ему еще пару

Назначение не будет работать, так как вы не можете ссылаться на reset. Однако вы можете копировать-инициализировать такие объекты.

Ответ 4

Вы правы. Вы можете создать пару ссылок, но больше не можете использовать operator =.

Ответ 5

Я думал по тому же пути, что и вы, я думаю. Я написал следующий класс, чтобы поцарапать этот особый зуд:

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;
}

(помните, что это относится).

Естественность - это, конечно, что ссылки на k и v, которые я назначаю, скрыты внутри 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;      
}

(Все комментарии приветствуются, поскольку я никоим образом не являюсь экспертом на С++.)

Ответ 6

Я не знаю, что является "неправильным" с std::pair в С++ 03, но если я переопределяю его наивно, у меня нет с ним никаких проблем (с использованием того же компилятора gcc и clang).

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) просто использовать С++ 11 (где 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;
        }
    };
}

Может быть, я пропустил что-то очевидное, я могу отредактировать ответ, если некоторые очевидные недостатки указаны.

Ответ 7

Я решил решить подобную проблему, просто построив действительно простую структуру. Я даже не беспокоился о операторе присваивания, так как по умолчанию он должен работать нормально.

template<class U, class V>
struct pair
{
pair(U & first, V & second): first(first), second(second) {}
U & first;
V & second;
}