f



822. Object with explicit copy constructor no longer CopyConstructible

Hi All,

 From the latest Standard Library active issues list:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2806.html

"
I just noticed that the following program is legal in C++03, but is
forbidden in the current draft:

     #include <vector>
     #include <iostream>

     class Toto
     {
     public:
         Toto() {}
         explicit Toto( Toto const& ) {}
     } ;

     int
     main()
     {
         std::vector< Toto > v( 10 ) ;
         return 0 ;
     }

Is this change intentional? (And if so, what is the justification? I
wouldn't call such code good, but I don't see any reason to break it
unless we get something else in return.)
"

1.  I don't understand why the program is now illegal.  std::vector
still offers a single int constructor that only requires its type to be
default constructable.  Does the explicit copy constructor make the
default constructor not visible?  Is this a language change or a library
change -- if the former, why is this issue in the Library Issues?

2.  Why is the code bad?  Is it because of the explicit copy
constructor?  Could that be a funny way of suppressing assignment form
initializers?  Or is it a no-op?


Geno Rice

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Eugene
12/12/2008 6:55:12 PM
comp.lang.c++.moderated 10738 articles. 1 followers. allnor (8506) is leader. Post Follow

1 Replies
360 Views

Similar Articles

[PageSpeed] 19

On 13 Dez., 01:55, Eugene Rice <g...@verizon.net> wrote:
>  From the latest Standard Library active issues list:
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2806.html
>
> "
> I just noticed that the following program is legal in C++03, but is
> forbidden in the current draft:
>
>      #include <vector>
>      #include <iostream>
>
>      class Toto
>      {
>      public:
>          Toto() {}
>          explicit Toto( Toto const& ) {}
>      } ;
>
>      int
>      main()
>      {
>          std::vector< Toto > v( 10 ) ;
>          return 0 ;
>      }
>
> Is this change intentional? (And if so, what is the justification? I
> wouldn't call such code good, but I don't see any reason to break it
> unless we get something else in return.)
> "
>
> 1.  I don't understand why the program is now illegal.  std::vector
> still offers a single int constructor that only requires its type to be
> default constructable.  Does the explicit copy constructor make the
> default constructor not visible?  Is this a language change or a library
> change -- if the former, why is this issue in the Library Issues?

The reason, why it is now excluded, is, because the definition of
the requirement CopyConstructible has changed. This happened with
the introduction of the new requirement MoveConstructible as of

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2284.pdf

Interestingly previous papers correctly took into account possibly
explicit c'tors, just compare with

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1771.html

IMO the current concepts related to "constructor" concepts
have the problem, that starting from the most fundamental
constructor-related concept is non-explicit, see 20.2.6 in
N2798:

auto concept HasConstructor<typename T, typename... Args> {
   T::T(Args...);
}

This is a basic weakness, because this would not make
it possible to express any explicit constructor by the
concepts std::HasConstructor, std::Constructible,
std::MoveConstructible, or std::CopyConstructible.
It also makes it impossible to let existing concepts
like std::ArithmeticLike fulfill std::HasConstructor,
which itself requires (at least) explicit c'tors:

explicit T::T(intmax_t);
explicit T::T(uintmax_t);
explicit T::T(long double);

This becomes obvious, if you compare this situation
with the example shown in [concept.map.fct]/4,
bullet 12:

concept IC<typename T> {
   T::T(int);
}
concept EC<typename T> {
   explicit T::T(int);
}
struct X {
   X(int);
};
struct Y {
   explicit Y(int);
};
concept_map IC<X> { } // OK
concept_map EC<X> { } // OK
concept_map IC<Y> { } // error: cannot copy-initialize Y from an int
concept_map EC<Y> { } // OK

So, the current draft definitively has to fix the
current hierarchy of library concepts described
in [utility.concepts].

> 2.  Why is the code bad?  Is it because of the explicit copy
> constructor?  Could that be a funny way of suppressing assignment form
> initializers?  Or is it a no-op?

Explicit copy constructors have some funny and sometimes
astonishing properties, e.g. the fact, that you cannot
invoke a function taking a type with such copy constructor
by value:

struct S {
   S(){}
   explicit S (S const&){}
} s;

void f(S){}

void g() {
     f(s); // Error
}

This constraint makes using such types with most
libraries (including the standard library) a pain.
If you would e.g. provide a functor or an iterator
with explicit copy constructor, it could never be
used with the manifold of algorithms provided by
[algorithms], because these basically always take
the arguments by value. Such functions have many
advantages and if you want to define a constexpr
function (a new feature for C++0x) you are required
to take arguments by value there.

HTH & Greetings from Bremen,

Daniel Kr�gler


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
daniel
12/13/2008 4:16:22 PM
Reply: