Boost logo

Boost :

From: Peter Dimov (pdimov_at_[hidden])
Date: 2004-02-10 10:08:01


David Abrahams wrote:
>
> OK, so 8.5.3/5 says:
>
> A temporary of type ``cv1 T2'' [sic] is created, and a constructor
> is called to copy the entire rvalue object into the temporary. The
> reference is bound to the temporary or to a sub-object within the
> temporary.*
>
> [Footnote: Clearly, if the reference initialization being processed
> is one for the first argument of a copy constructor call, an
> implementation must eventually choose the first alternative (binding
> without copying) to avoid infinite recursion. --- end foonote]
>
> The constructor that would be used to make the copy shall be
> callable whether or not the copy is actually done.
>
> The problem here is, IIUC, that the implementors read that as saying
> that, because "a constructor is called to copy..." that the
> constructor used must be a copy constructor?
>
> I don't understand why the converting constructor fails to be
> considered when the templated SFINAE'd constructor *will* be used to
> copy const lvalues. Templated constructors are never "copy ctors"
> either, IIUC.

It's a fine specimen of circular logic.

The compiler is allowed to elide a temporary created by a copy constructor.

The compiler is _not_ allowed to elide a temporary created by some other
constructor, because this changes observable behavior and is not explicitly
allowed.

The only copy constructor that can create a const temporary from an rvalue
is X::X(X const &) (default arguments and ellipsis aside.)

Therefore, once the compiler has decided to elide the temporary, it only
needs to check for X(X const &). If such a constructor does not exist or is
inaccessible, the elision of the temporary is illegal.

This behavior is perfectly safe and reasonable, _provided that_ the auto_ptr
loophole does not exist. It was never intended to exist. Everything that is
based on it goes against the core logic of the language.

Does it make sense?

Once we are on the topic. As I understand it, 8.5.3 is intended to allow
compilers to place ROM-able temporaries in ROM. Consider:

void f(int const & x);

int main()
{
    f(5);
}

The compiler can place a temporary of type "int const" and value 5 in ROM,
and pass its address to f. Similarly, in:

struct X
{
    int i;
    X(int i): i(i) {}
};

void f(X const & x);

int main()
{
    f( X(5) );
}

the compiler is allowed to construct a "X const" with a value of X(5) at
compile time and place it in ROM.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk