Re: error: no matching function for call to `Anton::Anton(Anton)`

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

although this thread seems to be closed, it seems necessary to me
to discuss some misunderstandings (as I believe).

> Hi Eric,
> 
> As per section 5.5 of Stroustrup's C++PL (3rd ed or special ed), a temporary object cannot be bound to a non-const reference.
>

I don't have the book in my office, but it is not true. Temporary object *can* be bound to non-const
references: A typical example is streaming via operator <<, that is, in

std::cout << "abc" << "xyz"; 

the first call to operator << returns a temporary which is then bound to the
first argument of operator <<, which is a non-const reference.

Or to give another example (a simplified version of a class for building up xml-expressions):

#include <iostream>
#include <ostream>

class Nat {
  int n;
public :
  Nat() : n(0) {}
  Nat& inc() { ++n; }
  friend inline std::ostream& operator <<(std::ostream& o, Nat x) {
    o << x.n;
  }
};

int main() {
  std::cout << Nat().inc().inc().inc() << "\n";
}

This is perfectly legal (and the output is "3").

As one finds it in ISO 14882:1998(E), Section 8.5.3,
initialisation of references is not primarily concerned
with constness, but with the distinction between lvalues and 
rvalues (every expression is either an lvalue or an rvalue).
The rule about reference binding is as simple (mainly) as follows:

A non-const reference can be bound only to lvalues,
while a const reference can be bound to lvalues and rvalues.

Now functions which return references return lvalues
([ISO], Section 5.2.2, point 10),
while constructors yield rvalues
([ISO], Section 5.2.3).

This explains why in the original example of Eric

Anton a[] = {Anton()};

we get an error: only a copy-constructor with a non-const references was
defined, and since the initialisation of the elements of array a happens
via the copy constructor, the copy constructor does not accept the rvalue
Anton().

But the member function ref() of Anton defined later yields an lvalue, and
thus

Anton a[] = {Anton().ref()};

is no problem. Just as an illustration:

#include <iostream>
#include <ostream>

class Anton {
  int n;
public :
  explicit Anton(int n) : n(n) {}
  Anton(Anton& a) : n(a.n) {}
  Anton& ref() { return *this; }
  friend inline std::ostream& operator <<(std::ostream& o, Anton a) {
  return o << a.n;
  }
};

int main() {
  Anton a[] = {Anton(1).ref(), Anton(0) = Anton(2), Anton(3).ref()};
  std::cout << a[0] << a[1] << a[2] << "\n";
  // output: 123
}

I very much recommend (for several reasons) to read

@Article{Hyslop2002ObjectfulLifetime,
  author = 	 {Jim Hyslop},
  title = 	 {Conversations: It's an Object-ful Lifetime},
  journal = 	 {C/C++ Users Journal},
  year = 	 2002,
  volume =	 20,
  number =	 12,
  month =	 {December},
  note =         {Can be downloaded from \url{http://www.cuj.com/documents/s=7976/cujcexp2012hyslop/}},
  annote =	 {Vorhanden. Explizite Typ-Konvertierungen geben R-Werte zurueck, Funktionen, die Referenzen zurueckgeben, aber L-Werte. Bezug zu "It's A Wonderful Life".}
}

which can be downloaded from the given url, and which discusses the same subject.

Oliver


[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux