std::par de referencias


¿Es válido tener un std::pair de referencias ? En particular, hay problemas con el operador de asignación ? De acuerdo con este enlace, no parece haber un tratamiento especial con operator=, por lo que el operador de asignación predeterminado no podrá generarse.

Me gustaría tener un pair<T&, U&> y poder asignarle otro par (de valores o referencias) y modificar los objetos apuntados.

 27
Author: Deduplicator, 2010-09-22

7 answers

No, no puede hacer esto de manera confiable en C++03, porque el constructor de pair toma referencias a T, y crear una referencia a una referencia no es legal en C++03.

Note que dije "confiablemente". Algunos compiladores comunes aún en uso (para GCC, probé GCC4.1, @Charles informaron GCC4.4.4) no permiten formar una referencia a una referencia, pero más recientemente lo permiten mientras implementan el colapso de referencia (T& es T si T es un tipo de referencia). Si su código usa tales cosas, no puede confiar en que funcione en otros compiladores hasta que lo pruebe y vea.

Parece que quieres usar 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;
 28
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:37

En C++11 se puede utilizar std::pair<std::reference_wrapper<T>, std::reference_wrapper<U>> y los objetos de ese tipo se comportarán exactamente como quieras.

 19
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-27 11:23:03

Creo que sería legal tener una std::pair referencias de vivienda. std::map usa std::pair con un tipo const, después de todo, que no se puede asignar a ninguno de los dos.

Me gustaría tener un pair<T&, U&> y poder asignarle otro par

La asignación no funcionará, ya que no se pueden restablecer las referencias. Sin embargo, puede copiar-inicializar dichos objetos.

 6
Author: sbi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-22 13:39:01

Tienes razón. Puede crear un par de referencias, pero ya no puede usar operator =.

 2
Author: ybungalobill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-22 13:38:16

Estaba pensando en la misma línea que usted, creo. Escribí la siguiente clase para rascar este picor en particular:

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

Te permite hacer cosas horribles como:

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

(recuerde las inclusiones relevantes).

El rudo es, por supuesto, que las referencias a k y v que estoy asignando están ocultos dentro de p. Casi se vuelve bonito de nuevo si haces algo como esto:

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

Que te permite hacer un bucle como este:

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

(Todos los comentarios son bienvenidos ya que de ninguna manera soy un experto en c++.)

 2
Author: MrMasterplan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-07 13:58:43

No se que es "malo" con std::pair en C++03 pero si lo reimplazo ingenuamente, no tengo ningún problema con él, (usando el mismo compilador gcc y 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.

Así que una solución podría ser (1) reimplementar pair (en un espacio de nombres diferente), o (2) especializarse para std::pair<T&, T&>, o (3) simplemente usar C++11 (donde std::pair para refs funciona fuera de la caja)

(1) Aquí está la implementación ingenua

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) Y aquí es una especialización de std::pair (algunas personas pueden me quejo de que estoy sobrecargando / especializándome con el espacio de nombres std, pero creo que está bien si es para extender las capacidades de la clase)

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

Tal vez me falta algo obvio, puedo editar la respuesta si algunos defectos obvios, se señalan.

 1
Author: alfC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-18 02:32:24

Terminé resolviendo un problema similar simplemente construyendo una estructura realmente simple. Ni siquiera me preocupé por el operador de asignación ya que el predeterminado debería funcionar bien.

template<class U, class V>
struct pair
{
pair(U & first, V & second): first(first), second(second) {}
U & first;
V & second;
}
 -1
Author: Zachary Kraus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-22 04:56:50