Newsgroup: it.comp.lang.c++
Titolo: Visual C++ vs G++ : problema di compilazione

Ciao a tutti,
questo codice viene compilato ed eseguito correttamente (?!) con MS Visual
C++ e causa il seguente errore con G++.
prova.cpp: In member function `Variant Connection::foo(int)':
prova.cpp:46: error: no match for 'operator=' in 'a =
Recordset::Get(int)(n)'
prova.cpp:15: error: candidates are: Variant& Variant::operator=(Variant&)
sono sicuro di sbagliare qualcosa ma non capisco cosa .. magari basta
inserire l'opzione corretta in G++ ....
(guardate solo la sintassi, il codice è insensato l'ho scritto solo per
riprodurre l'errore in un contesto + semplice dell'originario).
Grazie,
Alberto.
=================================================================
#include <stdio.h>
class Variant
{
public:
 int i;
 Variant(){i=0;};
 ~Variant(){i=0;};
 Variant (Variant &v)
 {
  i=v.i;
 };
 Variant &operator=(Variant &rhs)
 {
  i=rhs.i;
  return *this;
 }
};
class Recordset
{
public:
 double y;
 Recordset(){y=1.1;};
 ~Recordset(){};
 Variant Get(int x)
 {
  Variant temp;
  temp.i=x;
  return temp;
 };
};
class Connection : public Recordset
{
public:
 char c;
 Connection(){c='a';};
 ~Connection(){};
 Variant foo(int n)
 {
  Variant a;
  a = Get(n); // errore QUI !!
  return a;
 }
};
int main(int argc, char* argv[])
{
 Connection c;
 int h = c.foo(19).i;
 printf("Hello World!\n%d\n",h);
 return 0;
}

riprodurre l'errore in un contesto + semplice dell'originario).
Un caso ancora piu' semplice e' il seguente...
  struct X
  {
    X& operator=(X&)
    {
      return *this;
    }
  };
  X foo()
  {
    return X();
  }
  void bar()
  {
    X a;
    a = foo();  // <--- errore!
  }
Il problema e' che l'operatore di assegnazione che hai
definito accetta un reference non-const e quindi richiede
che venga passato un lvalue. Un oggetto tornato per valore
da una funzione non e' un lvalue e ha ragione g++ a non
compilare l'assegnazione. Sul draft dello standard questo
e' spiegato in 8.5.3 [dcl.init.ref] ai punti 5 e seguenti:
in pratica l'inizializzazione di un reference "cv1 T1" con
l'espressione "cv2 T2" si puo' fare se i tipi sono
compatibili e se:
  cv2 T2 e' un lvalue, oppure esiste una conversione che
  torna un lvalue (in questo caso il binding e' "diretto")
     oppure
  se cv1 T1 e' un const reference (in questo caso il
  binding viene fatto con una copia temporanea oppure
  con l'oggetto stesso, a scelta dell'implementazione).
Un oggetto tornato per valore da un funzione non e' un
lvalue ma un rvalue, e quindi puoi solo associarlo ad un
reference const. Quando chiami Variant::operator= invece
cerchi di associare il valore tornato da Get ad un
reference non const.
Per risolvere il tuo problema forse ti basta dichiarare
il parametro di operator= come "const Variant&".
Una alternativa (secondo me orrenda) e' quella di
scrivere una funzione "to_ref" che restituisce un
reference all'oggetto Variant...
    class Variant
    {
      ...
      Variant& to_ref()
      {
        return *this;
      }
    }
e poi usare
    Variant foo(int n)
    {
      Variant a;
      a = Get(n).to_ref();
      return a;
    }
Quello che sbaglia e' quindi il VC++ che ti lascia
compilare l'assegnazione, non g++.
HTH
Andrea