Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.std.c++ > #438

Re: Contradiction in the Standard. Overload resolution between copy constructor and template constructor

From Daniel Krügler <daniel.kruegler@googlemail.com>
Newsgroups comp.std.c++
Subject Re: Contradiction in the Standard. Overload resolution between copy constructor and template constructor
Date 2012-03-11 23:15 -0700
Organization A noiseless patient Spider
Message-ID <jji41u$bkd$1@dont-email.me> (permalink)
References <bcc4a1fd-b56c-4faf-ad07-e0dd380be37f@l12g2000yqi.googlegroups.com>

Show all headers | View raw


Am 11.03.2012 09:22, schrieb vlad.moscow@mail.ru:
>
> Early in the C++ Standard there was the phrase ( 12.8.7 ) "7 A member
> function template is never instantiated to perform the copy of a class
> object to an object of its
> class type."


[Let me start with a remark: Please don't quote C++ Standard phrases
by merging sub-clause and paragraph in a single "quotation
coordinate". "12.8.7" should be quoted as "12.8 p(aragraph) 7", for
example]

Note that this particular wording was recognized as a defect and was
fixed for C++11 by

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1080

It was already true in C++03 that copy-constructors participate in
overload resolution in several situations, so this fix is just a
clean-up of an obvious inconsistency in the standard.

> However as it follows from the Standard a template constructor takes
> part in overload resolution even for copy initialization.


Exactly, and this was already true in certain situations in C++03.
C++11 ensured that this is now a much more consistent scheme. See also

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#535

for one of the most recent wording fixes in this regard.

> Let consider an example.
>
> #include<iostream>
>
> struct A
> {
>        template<class T>
>        A( T&  ) { std::cout<<  "template<class T>  A( T&  )\n"; }
> };
>
> void f1( A a ) {}
>
> void f2( A a )
> {
>        f1( a );
> }
>
> void f3( const A&a )
> {
>        f1( a );
> }
>
> int main()
> {
>        int i = 10;
>        A a( i );
>
>        f2( a );
>        f3( a );
>
>        return ( 0 );
> }
>
> Here the template constructor is called three times. the first time
> then object a is created. The second and the third time then it passed
> to function f2 and correspondingly to function f1. At least I checked
> this with several compilers.


I think the compiler behaviour is conforming: In these cases the
template constructor is a better match, because the arguments are
non-const. The implicit copy-constructor has the signature

A(const A&)

in this case.

> And the implicit copy constructor is called two times then object a is
> passed to function f3 and correspondingly to function f1, because the
> parameter of f3 declared as const reference.


I count only one call to the copy constructor when f1 is called from f3.

> According to the Standard ( 12.8.1 ) "1 A class object can be copied
> or moved in two ways: by initialization (12.1, 8.5), including for
> function argument
> passing (5.2.2) and for function value return (6.6.3); and by
> assignment (5.17). Conceptually, these two operations are implemented
> by a copy/move constructor (12.1) and copy/move assignment operator
> (13.5.3)."
> Take into account what is writtten: that copying is implemented by
> copy constructor.
> On the other hand there is the folloing phrase in the Standard
> ( 12.8.2 ): " 2 A non-template constructor for class X is a copy
> constructor if its first parameter is of type X&, const X&, volatile
> X&  or const volatile X&, and either there are no other parameters or
> else all other parameters have default arguments (8.3.6). [ Example:
> X::X(const X&) and X::X(X&,int=1) are copy constructors."
>
> Again take into account that the copy constructor is a non-template
> constructor. However in the example I have shown above the template
> consttructor was called for coping initialization.


This is not a contradiction, because there are two different concepts involved:

a) The definition of a copy/move constructor, which is a special
member function and by this role they still have a special meaning in
the language, e.g. when defining trivial types.

b) The functions considered during overload resolution. With this
definition in mind, copy/move constructors are just *candidates*, but
not necessarily the best match per se.

> Let consider another example
>
> #include<iostream>
>
> struct A
> {
>        template<class T>
>        A( T&  ) { std::cout<<  "template<class T>  A( T&  )\n"; }
> private:
>        A( const A&  ) {}
>
> };
>
> void f1( A a ) {}
>
> void f2( A a )
> {
>        f1( a );
> }
>
>
> int main()
> {
>        int i = 10;
>        A a( i );
>
>        f2( a );
>
>        return ( 0 );
> }
>
>
> Here again the template constructor is called though the copy
> constructor is explicitly defined as private.


Well, this behaviour is consistent, right? If it were different, we
would have an inconsistency in regard to overload selection rules. The
language is clear, that access checks happen *after* overload
resolution. So given the fact that the template constructor is
selected in preference over the copy/move constructor it would be
astonishing, if the code would not be accepted by the compiler.

> I see here a contradiction and broken semantic of the copy
> constructor. It follows that in fact a template constructor is a copy
> constructor and role of the copy consttructor totally unclear if we
> can do all with a template constructor. So one can say that a copy
> consttructor is in fact any constructor template or non-template which
> takes a reference to object of the same class as a parameter.


The point of misunderstanding is the difference between the term
"copy/move constructor" and the term "constructor selected to
copy/move". The most recent draft N3376 uses the second term when
referring to the effective constructor used for a copy/move operation.
E.g. 3.2 p3 says now:

"A constructor selected to copy or move an object of class type is
odr-used [..]"

But I agree that your mentioned sentence in [class.copy] p1

"Conceptually, these two operations are implemented by a copy/move
constructor (12.1) and copy/move assignment operator (13.5.3)."

is a bit misleading now.

HTH & Greetings from Bremen,

Daniel Krügler


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]

Back to comp.std.c++ | Previous | NextPrevious in thread | Next in thread | Find similar


Thread

Contradiction in the Standard. Overload resolution between copy  constructor and template constructor vlad.moscow@mail.ru - 2012-03-11 00:22 -0800
  Re: Contradiction in the Standard. Overload resolution between copy  constructor and template constructor Daniel Krügler <daniel.kruegler@googlemail.com> - 2012-03-11 23:15 -0700
    Re: Contradiction in the Standard. Overload resolution between copy   constructor and template constructor vlad.moscow@mail.ru - 2012-03-12 09:17 -0700
      Re: Contradiction in the Standard. Overload resolution between copy    constructor and template constructor Daniel Krügler<daniel.kruegler@googlemail.com> - 2012-03-13 09:07 -0700

csiph-web