Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Binding reference to rvalue - compilers disagree

17 views
Skip to first unread message

Rani Sharoni

unread,
Jan 2, 2003, 4:09:11 PM1/2/03
to
Hello All:

Consider the following code:

template<typename T> struct D : T {};

struct A {
A();
A(A&);
A(D<A>&);
operator D<A>&();
};

int f(const A &);
int x = f(A()); // (*) EDG 3.0 - "A::A(A &)", required for copy that
was eliminated, is not callable because reference parameter cannot be
bound to rvalue.

VC7.1, GCC 3.2 and BCC 5.5 accepted (*).
After reading 8.5/14/4/2, 8.5.3/5/2/1 and core issue #291 it seems to
me that (*) is legal – semantically construct the temporary, from the
rvalue, using A(D<A>&) and bind it to the reference.

Can anyone tell whether the above code is legal?

Thanks,
Rani

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

Alberto Barbati

unread,
Jan 2, 2003, 7:30:20 PM1/2/03
to
Rani Sharoni wrote:
> Hello All:
>
> Consider the following code:
>
> template<typename T> struct D : T {};
>
> struct A {
> A();
> A(A&);
> A(D<A>&);
> operator D<A>&();
> };
>
> int f(const A &);
> int x = f(A()); // (*) EDG 3.0 - "A::A(A &)", required for copy that
> was eliminated, is not callable because reference parameter cannot be
> bound to rvalue.
>
> VC7.1, GCC 3.2 and BCC 5.5 accepted (*).
> After reading 8.5/14/4/2, 8.5.3/5/2/1 and core issue #291 it seems to
> me that (*) is legal – semantically construct the temporary, from the
> rvalue, using A(D<A>&) and bind it to the reference.
>
> Can anyone tell whether the above code is legal?

Either I don't understand the question or the code does not match with
it... the conversions to and from D<A> are completely irrelevant!

1) function f takes a const A& parameter
2) A() is an expression that evaluates to a temporary object of type A
3) the temporary object is bound to the const A&

Why should the compiler attempt to perform a conversion when the
expression is already the exact type it need it to be?

Alberto

-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 80,000 Newsgroups - 16 Different Servers! =-----

Rani Sharoni

unread,
Jan 3, 2003, 11:40:21 AM1/3/03
to
abar...@iaanus.com (Alberto Barbati) wrote in message news:<3e14d054$1...@corp.newsgroups.com>...

> Rani Sharoni wrote:
> > Hello All:
> >
> > Consider the following code:
> >
> > template<typename T> struct D : T {};
> >
> > struct A {
> > A();
> > A(A&);
> > A(D<A>&);
> > operator D<A>&();
> > };
> >
> > int f(const A &);
> > int x = f(A()); // (*) EDG 3.0 - "A::A(A &)", required for copy that
> > was eliminated, is not callable because reference parameter cannot be
> > bound to rvalue.
> >
> > VC7.1, GCC 3.2 and BCC 5.5 accepted (*).
> > After reading 8.5/14/4/2, 8.5.3/5/2/1 and core issue #291 it seems to
> > me that (*) is legal semantically construct the temporary, from the
> > rvalue, using A(D<A>&) and bind it to the reference.
> >
> > Can anyone tell whether the above code is legal?
>
> Either I don't understand the question or the code does not match with
> it... the conversions to and from D<A> are completely irrelevant!

Try to compile the code using Comeau (EDG based) online:
http://www.comeaucomputing.com/tryitout

> 1) function f takes a const A& parameter
> 2) A() is an expression that evaluates to a temporary object of type A
> 3) the temporary object is bound to the const A&

This is exactly what VC, GCC and BCC did.

> Why should the compiler attempt to perform a conversion when the
> expression is already the exact type it need it to be?

8.5.3/5/2/1:
<quote>
If the initializer expression is an rvalue, with T2 a class type, and
"cv1 T1" is reference compatible with "cv2 T2", the reference is bound
in one of the following ways (the choice is implementation defined):

- The reference is bound to the object represented by the rvalue (see
3.10) or to a subobject within that object.

- 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 subobject within the
temporary.93)

The *constructor* that would be used to make the copy shall be
callable whether or not the copy is actually done.
</quote>

One rational is that the rvalue storage might be a register.

My question is whether A(D<A>&) could be the constructor that
mentioned at 8.5.3/5/2/1 (notice that D<A> is derived from A) since
the ctor isn't viable (i.e. EDG diagnostic).

Thanks,
Rani

Graeme Prentice

unread,
Jan 3, 2003, 7:24:05 PM1/3/03
to

8.5.3 para 5 specifies it is implementation defined whether a
constructor is called to create a temporary that can be bound to the
const&.

Comeau 4.3.0.1 gives a compiler warning that the copy constructor was
uncallable but that the copying was eliminated anyway and attempts to
link and complains of unresolved externals for the default constructor
and the function f().

The compiler is allowed to use a conversion function that returns a
non const &A and bind that to the function f const A& parameter but
there is no such conversion function applicable in this case so it is
entitled to want to call a constructor to create a new temporary (even
if it doesn't actually call it, it is entitled to apply all the
associated requirements as if it did).

It can't call the copy constructor to create a new temporary because
that is declared with a non const& param. It can't directly call the
constructor that takes a non const D<A>& but it can call the non const
conversion function which returns a non const D<A>& that can be passed
to the constructor taking D<A>.

Active issue 291 that Rani mentioned discusses the fact that the std
doesn't specify any details of how the "new" temporary object is
constructed e.g. whether it's direct initialisation ( T x(a) ) or
copy initialisation ( T x = a ) (8.5 para 12) - these have
different rules applying to them.

So we're trying to construct an A object from an A object using a
constructor and the standard doesn't say any more than suggest that
any constructor may be used but recursion must be avoided (by not
creating a new temporary at all - which doesn't apply in this case -
if the copy constructor is the function we're eventually trying to
call then we can't call it in the process of trying to call it !!)

It shouldn't actually matter whether copy-init or direct-init is
applied because in the case of copy-init, if the source type is the
same as the destination type then the behaviour is the same as for
direct-init and a copy constructor isn't necessarily used ( 8.5 para
14/4/2 that Rani mentioned). Active issue 291 suggests direct
initialisation should be used.


This code uses direct initialisation to create the y object and
copy-init for z. Comeau linker complains of unresolved external for
the operator D<A> and the constructor taking D<A>. GCC 3.2 gets a
"parse error" for the declaration of y and ambiguity for z (GCC thinks
the copy constructor is a candidate but I don't think it is because
there's no special rule that allows the non const reference in the
copy constructor to bind to a temporary).

template<typename T> struct D : T {};

struct A {
A();
A( A&);
A(D<A>&);
operator D<A>&();
};

int f(const A & b);
//int x = f(A());

int main()
{
A y( (A()) ); // direct init
A z = A(); // copy init
}


Graeme

Anthony Williams

unread,
Jan 3, 2003, 7:24:22 PM1/3/03
to
abar...@iaanus.com (Alberto Barbati) writes:

> Rani Sharoni wrote:
> > template<typename T> struct D : T {};
>
> > struct A {
>
> > A(); A(A&);
>
> > A(D<A>&);
> > operator D<A>&();
> > };
> > int f(const A &);
>
> > int x = f(A()); // (*) EDG 3.0 - "A::A(A &)", required for copy that
> > was eliminated, is not callable because reference parameter cannot be
> > bound to rvalue.
> > VC7.1, GCC 3.2 and BCC 5.5 accepted (*).
>
> > After reading 8.5/14/4/2, 8.5.3/5/2/1 and core issue #291 it seems to
> > me that (*) is legal – semantically construct the temporary, from the
> > rvalue, using A(D<A>&) and bind it to the reference.
> > Can anyone tell whether the above code is legal?
>
>
> Either I don't understand the question or the code does not match with
> it... the conversions to and from D<A> are completely irrelevant!
>
>
> 1) function f takes a const A& parameter
> 2) A() is an expression that evaluates to a temporary object of type A
> 3) the temporary object is bound to the const A&
>
> Why should the compiler attempt to perform a conversion when the expression
> is already the exact type it need it to be?

When binding an rvalue to a const reference the compiler is permitted to make
a temporary copy of the rvalue and bind the reference to that copy. Therefore
the constructor which would be used to create this copy must be accessible
whether or not the copy is actually made.

The issue (which is highlighted in core issue 291) is whether this has to be a
copy constructor, or whether other constructors can be considered. Indeed, the
example given by Rani above is almost identical to that given in issue 291 ---
the copy constructor takes a non-const ref, so cannot be used to make a copy,
but a user-defined conversion/converting-constructor pair can be used.

I am not sure whether this is legal or not, and I suppose we really need to
wait for the resolution of issue 291.

Anthony
--
Anthony Williams
Senior Software Engineer, Beran Instruments Ltd.
Remove NOSPAM when replying, for timely response.

Alberto Barbati

unread,
Jan 3, 2003, 7:27:30 PM1/3/03
to
Hi Rani,

now I got the whole picture! The question makes now sense to me. Thanks
for your clear and patient explanation.

>>>Consider the following code:
>>>
>>>template<typename T> struct D : T {};
>>>
>>>struct A {
>>> A();
>>> A(A&);
>>> A(D<A>&);
>>> operator D<A>&();
>>>};
>>>
>>>int f(const A &);
>>>int x = f(A()); // (*) EDG 3.0 - "A::A(A &)", required for copy that
>>>was eliminated, is not callable because reference parameter cannot be
>>>bound to rvalue.

In light of what you said, I can understand EDG. It needs (or just
wants) to make a copy of the temporary and this is allowed because the
choice is explicitly said to be implementation-defined. Yet, it cannot
use the copy ctor on the temporary because it has been defined as A(A&)
instead of A(const A&).

[I still don't agree with the compiler choice, though... what's the
point in requiring the copy and then elimitate it, when it can choose
the alternative path "binding without copying"? Doh!]

If it were not for the D<A> stuff that would conclude the discussion.
But... then there's your question:

> My question is whether A(D<A>&) could be the constructor that
> mentioned at 8.5.3/5/2/1 (notice that D<A> is derived from A) since
> the ctor isn't viable (i.e. EDG diagnostic).

I'm just speculating, I'm not a field expert. In order to use A(D<A>&)
we need an object of type D<A> in the first place. So we have to call
operator D<A>&() before. But that would account to two implicit
user-defined conversion to a single value, a choice that cannot be made
per 12.3 (clause 4), IMHO.

The thing gets more interesting if we define the conversion operator as
returning a const D<A>&. In this case, the compiler could choose to bind
to a sub-object without copying.

Alberto

-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 80,000 Newsgroups - 16 Different Servers! =-----

---

Rani Sharoni

unread,
Jan 4, 2003, 4:23:07 AM1/4/03
to
anthony.wil...@anthonyw.cjb.net (Anthony Williams) wrote in message news:<k7hmlf...@anthonyw.cjb.net>...

> abar...@iaanus.com (Alberto Barbati) writes:
>
> > Rani Sharoni wrote:
> > > template<typename T> struct D : T {};
>
> > > struct A {
>
> > > A(); A(A&);
>
> > > A(D<A>&);
> > > operator D<A>&();
> > > };
> > > int f(const A &);
>
> > > int x = f(A()); // (*) EDG 3.0 - "A::A(A &)", required for copy th
> at
> > > was eliminated, is not callable because reference parameter cannot be
> > > bound to rvalue.
> > > VC7.1, GCC 3.2 and BCC 5.5 accepted (*).
>
> > > After reading 8.5/14/4/2, 8.5.3/5/2/1 and core issue #291 it seems to
> > > me that (*) is legal semantically construct the temporary, from t
> he
> > > rvalue, using A(D<A>&) and bind it to the reference.
> > > Can anyone tell whether the above code is legal?
> > [...]

> >
> > Why should the compiler attempt to perform a conversion when the expres
> sion
> > is already the exact type it need it to be?
> [...]

> The issue (which is highlighted in core issue 291) is whether this has to
> be a
> copy constructor, or whether other constructors can be considered.

I don't think that this is the problem mentioned at #291. The question
there is whether the temporary is initialized using copy
initialization or direct initialization and as Graeme Prentice noted
in his detailed post it doesn't make a difference in the code I showed
(which indeed similar to the one presented at #291). The fact that
D<A> derived from A "convinced" VC7.1 that the code is well-formed but
I'm not sure that it's related.

According to #291 the copy constructor restriction was removed so that
other constructors might be used to initialize the temporary.
The rational behind that extra copying is understandable (e.g. the
rvalue storage is a register or implementation issues related to
operator ?:) and I think that the construction I mentioned (A(D<A>&)
using operator D<A>&()) and also mentioned at #291 is good enough to
perform this task.

The problem of binding rvalue to const reference (indicated by peter
dimov) broke the original implementation of Andrei's MoJo which was
cleaner then the current one. The minor "correction" (using derivation
of D<A> from A) makes the original implementation usable, for now,
with VC7.1.

Rani

Raoul Gough

unread,
Jan 5, 2003, 10:46:45 PM1/5/03
to
"Rani Sharoni" <rani_s...@hotmail.com> wrote in message
news:df893da6.03010...@posting.google.com...

> anthony.wil...@anthonyw.cjb.net (Anthony Williams) wrote in
message news:<k7hmlf...@anthonyw.cjb.net>...
[snip]

> > The issue (which is highlighted in core issue 291) is whether this
has to
> > be a
> > copy constructor, or whether other constructors can be considered.
[snip]

> The problem of binding rvalue to const reference (indicated by peter
> dimov) broke the original implementation of Andrei's MoJo which was
> cleaner then the current one. The minor "correction" (using
derivation
> of D<A> from A) makes the original implementation usable, for now,
> with VC7.1.

I'm still trying to understand what the standard's requirement is
supposed to achieve in this situation, except annoy programmers. I've
never been convinced by that "rvalue in a register" argument - are
there any other reasons for it?

BTW, the reason I don't buy the register business is that you can
force a reference to bind *directly* to the rvalue via a member
function, so either the compiler can handle this or it can't return
rvalues in a register.

Regards,
Raoul Gough.

Rani Sharoni

unread,
Jan 6, 2003, 1:21:56 PM1/6/03
to

""Raoul Gough"" <Raoul...@yahoo.co.uk> wrote in message
news:av94gt$cujtg$1...@ID-136218.news.dfncis.de...

> "Rani Sharoni" <rani_s...@hotmail.com> wrote in message
> news:df893da6.03010...@posting.google.com...
> > anthony.wil...@anthonyw.cjb.net (Anthony Williams) wrote in
> message news:<k7hmlf...@anthonyw.cjb.net>...
> [snip]
> > > The issue (which is highlighted in core issue 291) is whether this
> has to
> > > be a
> > > copy constructor, or whether other constructors can be considered.
> [snip]
> > The problem of binding rvalue to const reference (indicated by peter
> > dimov) broke the original implementation of Andrei's MoJo which was
> > cleaner then the current one. The minor "correction" (using
> derivation
> > of D<A> from A) makes the original implementation usable, for now,
> > with VC7.1.
>
> I'm still trying to understand what the standard's requirement is
> supposed to achieve in this situation, except annoy programmers. I've
> never been convinced by that "rvalue in a register" argument - are
> there any other reasons for it?

I totally agree with your proposal for relaxation of this requirement:
http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&safe=off&selm=ar056p%24e5
dno%241%40ID-136218.news.dfncis.de

I actually did notice one case when the implementation (VC) actually used
the extra copying freedom:
extern "C" int printf(const char *, ...);

struct A {
A(const A&) { printf("A::A(const A&)\n"); }
A() {}
};

int main(int argc, char **) {
const A& x = argc ? A() : A();
}

Output (optimized code): A::A(const A&)

I notice that your proposal also covers this issue (temporary lifetime) and
allow the implementation doing so in such context.
Notice the lifetime of the temporary in the above code is also problematic
issue (core issue 86).

Rani

Anthony Williams

unread,
Jan 6, 2003, 1:29:25 PM1/6/03
to
rani_s...@hotmail.com (Rani Sharoni) writes:

> anthony.wil...@anthonyw.cjb.net (Anthony Williams) wrote in message
> news:<k7hmlf...@anthonyw.cjb.net>...

> I don't think that this is the problem mentioned at #291. The question
> there is whether the temporary is initialized using copy
> initialization or direct initialization and as Graeme Prentice noted
> in his detailed post it doesn't make a difference in the code I showed
> (which indeed similar to the one presented at #291). The fact that
> D<A> derived from A "convinced" VC7.1 that the code is well-formed but
> I'm not sure that it's related.

I was referring to the example:

"Furthermore, now that the set of candidate functions is not limited to only
the copy constructors of T2, there might be some unpleasant
consequences. Consider a rather contrived sample below:

int * pi = ::new(std::nothrow) int;
const std::auto_ptr<int> & ri = std::auto_ptr<int>(pi);"

which is similar to the user-defined-conversion operator/constructor pair in
your example



> According to #291 the copy constructor restriction was removed so that
> other constructors might be used to initialize the temporary.

Yes, in particular templated constructors.

> The rational behind that extra copying is understandable (e.g. the
> rvalue storage is a register or implementation issues related to
> operator ?:) and I think that the construction I mentioned (A(D<A>&)
> using operator D<A>&()) and also mentioned at #291 is good enough to
> perform this task.

Direct vs Copy initialization is not an issue here, but it would be if the
constructor was explicit.



> The problem of binding rvalue to const reference (indicated by peter
> dimov) broke the original implementation of Andrei's MoJo which was
> cleaner then the current one. The minor "correction" (using derivation
> of D<A> from A) makes the original implementation usable, for now,
> with VC7.1.

I was aware of this. Indeed, I thought your post was really questioning the
legality of Andrei's MoJo technique, without mentioning it by name ;-)

Anthony
--
Anthony Williams
Senior Software Engineer, Beran Instruments Ltd.
Remove NOSPAM when replying, for timely response.

---

Raoul Gough

unread,
Jan 7, 2003, 7:29:17 PM1/7/03
to
""Rani Sharoni"" <rani_s...@hotmail.com> wrote in message
news:3e194b28$1...@news.microsoft.com...

> ""Raoul Gough"" <Raoul...@yahoo.co.uk> wrote in message
> news:av94gt$cujtg$1...@ID-136218.news.dfncis.de...
[snip]

> > I'm still trying to understand what the standard's requirement is
> > supposed to achieve in this situation, except annoy programmers.
I've
> > never been convinced by that "rvalue in a register" argument - are
> > there any other reasons for it?
>
> I totally agree with your proposal for relaxation of this
requirement:
>
http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&safe=off&selm=ar056
p%24e5
> dno%241%40ID-136218.news.dfncis.de
>

You and I seem to be the only ones who like this idea, though! Maybe
if more compilers actually enforced this rule, there would be interest
in relaxing it officially.

> I actually did notice one case when the implementation (VC) actually
used
> the extra copying freedom:
> extern "C" int printf(const char *, ...);
>
> struct A {
> A(const A&) { printf("A::A(const A&)\n"); }
> A() {}
> };
>
> int main(int argc, char **) {
> const A& x = argc ? A() : A();
> }
>
> Output (optimized code): A::A(const A&)
>
> I notice that your proposal also covers this issue (temporary
lifetime) and
> allow the implementation doing so in such context.
> Notice the lifetime of the temporary in the above code is also
problematic
> issue (core issue 86).

Yes, the argument about member functions doesn't apply in this case,
because the reference extends the lifetime of the temporary (which
can't be done if the reference comes back from a member function). It
would be interesting to know what VC++ does if you pass that rvalue to
a function instead of binding it to a longer-lived reference. Assuming
it uses a copy in that case as well, the next question would be what
does it do with

f ((argc ? A() : A()).get_ref())

Regards,
Raoul Gough.

Rani Sharoni

unread,
Jan 8, 2003, 1:02:58 PM1/8/03
to

""Raoul Gough"" <Raoul...@yahoo.co.uk> wrote in message
news:aveoj5$esipa$1...@ID-136218.news.dfncis.de...

> ""Rani Sharoni"" <rani_s...@hotmail.com> wrote in message
> news:3e194b28$1...@news.microsoft.com...
> > ""Raoul Gough"" <Raoul...@yahoo.co.uk> wrote in message
> > news:av94gt$cujtg$1...@ID-136218.news.dfncis.de...
> [snip]
> > > I'm still trying to understand what the standard's requirement is
> > > supposed to achieve in this situation, except annoy programmers.
> I've
> > > never been convinced by that "rvalue in a register" argument - are
> > > there any other reasons for it?
> >
> > I totally agree with your proposal for relaxation of this
> requirement:
> >
> http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&safe=off&selm=ar056
> p%24e5
> > dno%241%40ID-136218.news.dfncis.de
> >
>
> You and I seem to be the only ones who like this idea, though! Maybe
> if more compilers actually enforced this rule, there would be interest
> in relaxing it officially.
I "hope" to see one compiler that makes the extra copying and doesn't follow
your suggestion.

> > Notice the lifetime of the temporary in the above code is also
problematic
> > issue (core issue 86).
>
> Yes, the argument about member functions doesn't apply in this case,
> because the reference extends the lifetime of the temporary (which
> can't be done if the reference comes back from a member function). It
> would be interesting to know what VC++ does if you pass that rvalue to
> a function instead of binding it to a longer-lived reference. Assuming
> it uses a copy in that case as well, the next question would be what
> does it do with
>
> f ((argc ? A() : A()).get_ref())

When passing the rvalue to a function VC didn't made the extra copying.
For looking at the generated assembly I saw that:
f(cond ? A(1) : A(2))
transformed to:
if (cond) f(A(1)) else f(A(2));

Rani

Rani Sharoni

unread,
Jan 8, 2003, 3:33:42 PM1/8/03
to

"Anthony Williams" <anthony.wil...@anthonyw.cjb.net> wrote in
message news:u1gmh9...@anthonyw.cjb.net...
> rani_s...@hotmail.com (Rani Sharoni) writes:
> [...]

> > According to #291 the copy constructor restriction was removed so that
> > other constructors might be used to initialize the temporary.
>
> Yes, in particular templated constructors.

I wonder if Steve Adamczyk ment for something like the following:
struct A {
A();
A(A&);
template<typename T> A(const T&);
};

const A& x = A(); // semanticly uses the template constructor

According to 12.8/2 note 106 the template constructor can't be a copy
constructor but I can't see any differant in the above class usage if it
was.

Anyway, I think that any well-formed way to construct the temporary
mentioned at 8.5.3/5/2/1 is acceptable - even the one mentioned at core
issue #291 (auto_ptr).

What is the problem with my example when the following is allowed (one user
defined conversion and one construction)?

struct B { B(int); };

const B& y = 1; // 8.5.3/5/2/2 - Construct the temporary using copy
initialization and bind the reference to it.

This mean that the r-value is converter to B using B(int) and then,
semantically, copied to the temporary using B(const &).

EDG seems to miss that point since the following complied using Comeau C/C++
4.3.0.1:

struct B {

B(int);

private:

B(const B&);

};

const B& y = 1; // accepted by EDG 3.0

Both VC and GCC rejected the code.

I hope that someone from EDG will make things clearer and tell us if the
following is well formed:

struct A {

A();

A(A&);

A(int&);

operator int&();

};

const A& x = A(); // rejected by EDG

Accepted by VC, GCC and BCC even if A(int&) is private.

Is such construction (using operator int&() and A(int&)) is to surprising
for the programmer and should be forbidn?

Thanks,

Rani

Rani Sharoni

unread,
Jan 9, 2003, 1:49:06 PM1/9/03
to

""Rani Sharoni"" <rani_s...@hotmail.com> wrote in message
news:3e1b...@news.microsoft.com...

>
> "Anthony Williams" <anthony.wil...@anthonyw.cjb.net> wrote in
> message news:u1gmh9...@anthonyw.cjb.net...
> > rani_s...@hotmail.com (Rani Sharoni) writes:
> > [...]
> > > According to #291 the copy constructor restriction was removed so that
> > > other constructors might be used to initialize the temporary.
> >
> > Yes, in particular templated constructors.
>
> I wonder if Steve Adamczyk ment for something like the following:
> struct A {
> A();
> A(A&);
> template<typename T> A(const T&);
> };
>
> const A& x = A(); // semanticly uses the template constructor
>
> According to 12.8/2 note 106 the template constructor can't be a copy
> constructor but I can't see any differant in the above class usage if it
> was.
After reading 12.8/8 I undersatnd that there is a difference in the usage:

struct B : A {};
B b = B(); // Fail - A has no viable copy constructor

Anthony Williams

unread,
Jan 9, 2003, 5:30:20 PM1/9/03
to
rani_s...@hotmail.com ("Rani Sharoni") writes:

> "Anthony Williams" <anthony.wil...@anthonyw.cjb.net> wrote in
> message news:u1gmh9...@anthonyw.cjb.net...
> > rani_s...@hotmail.com (Rani Sharoni) writes:
> > [...]
> > > According to #291 the copy constructor restriction was removed so that
> > > other constructors might be used to initialize the temporary.
> >
> > Yes, in particular templated constructors.
>
> I wonder if Steve Adamczyk ment for something like the following:
> struct A {
> A();
> A(A&);
> template<typename T> A(const T&);
> };
>
> const A& x = A(); // semanticly uses the template constructor
>
> According to 12.8/2 note 106 the template constructor can't be a copy
> constructor but I can't see any differant in the above class usage if it
> was.

Not here, since you have explicitly declared a copy constructor. If you
hadn't, then the template wouldn't prevent the implicit declaration of the
default copy constructor.



> Anyway, I think that any well-formed way to construct the temporary
> mentioned at 8.5.3/5/2/1 is acceptable - even the one mentioned at core
> issue #291 (auto_ptr).
>
> What is the problem with my example when the following is allowed (one user
> defined conversion and one construction)?
>
>
>
> struct B { B(int); };
>
> const B& y = 1; // 8.5.3/5/2/2 - Construct the temporary using copy
> initialization and bind the reference to it.

I don't see a problem, it's just that in the example case, the type on the RHS
is the same as the type on the LHS, so there _may_ be a special-case rule
(like the rule that declaring an operator T&() as a member of the same type T
is not useful --- it will never be chosen implicitly, and can only be called
explicitly)

> This mean that the r-value is converter to B using B(int) and then,
> semantically, copied to the temporary using B(const &).
>
> EDG seems to miss that point since the following complied using Comeau C/C++
> 4.3.0.1:
>
> struct B {
>
> B(int);
>
> private:
>
> B(const B&);
>
> };
>
> const B& y = 1; // accepted by EDG 3.0
>
> Both VC and GCC rejected the code.
>
>
>
> I hope that someone from EDG will make things clearer and tell us if the
> following is well formed:
>
> struct A {
>
> A();
>
> A(A&);
>
> A(int&);
>
> operator int&();
>
> };
>
>
>
> const A& x = A(); // rejected by EDG

Presumably they don't think it is, then ;-)

> Accepted by VC, GCC and BCC even if A(int&) is private.

I'm not sure _that_ is allowed (and it means that VC and GCC contradict
themselves, cf your example with B above).

> Is such construction (using operator int&() and A(int&)) is to surprising
> for the programmer and should be forbidn?

Well, it is surprising, but that doesn't mean it should be forbidden, since
the circumstances are sufficiently rare.

Anthony
--
Anthony Williams
Senior Software Engineer, Beran Instruments Ltd.
Remove NOSPAM when replying, for timely response.

---

0 new messages