template copy constructor vs normal copy constructor

Discussion in 'C++' started by cinsk, Sep 26, 2010.

  1. cinsk

    cinsk Guest

    hi.

    I just read the definition of the std::pair in <utility>. std::pair
    has following two copy constructors:

    template <class T1, class T2>
    struct pair {

    pair::pair(const pair &);

    template<class U1, class U2> pair::pair(const pair<U1, U2> &);
    ...
    };

    The definition of both copy constructor looks same in my gentoo Linux/
    gcc 4.4.3.

    Although I'm not good at template, both copy constructors look same to
    me.

    Q1. What is the purpose of the second copy constructor?
    Could you give me some short example code that actually calls
    the second copy constructor?

    Q2. What happen if the second copy construct is missing?

    Q3. How can the compiler determine which copy constructor is used?
    In my poor understanding, it looks like that compile would
    complain for the ambiguity.

    Q4. If I want to make a template class, do I need to provide both copy
    constructor?
    If not, which is better? And why?

    Thank you.
    cinsk, Sep 26, 2010
    #1
    1. Advertising

  2. cinsk

    Kai-Uwe Bux Guest

    cinsk wrote:

    > hi.
    >
    > I just read the definition of the std::pair in <utility>. std::pair
    > has following two copy constructors:
    >
    > template <class T1, class T2>
    > struct pair {
    >
    > pair::pair(const pair &);
    >
    > template<class U1, class U2> pair::pair(const pair<U1, U2> &);
    > ...
    > };
    >
    > The definition of both copy constructor looks same in my gentoo Linux/
    > gcc 4.4.3.
    >
    > Although I'm not good at template, both copy constructors look same to
    > me.
    >
    > Q1. What is the purpose of the second copy constructor?
    > Could you give me some short example code that actually calls
    > the second copy constructor?


    It allows to copy construct a std::pair<double,double> from a
    std::pair<int,int>.

    > Q2. What happen if the second copy construct is missing?


    The above would not be possible

    > Q3. How can the compiler determine which copy constructor is used?
    > In my poor understanding, it looks like that compile would
    > complain for the ambiguity.


    The ambiguity you worry about arises as copy-constructing std::pair<int,int>
    from std::pair<int,int> matches both. That is true. In that case, overload
    resolution kicks in. In this case, the ambiguity is resolved in favor of the
    non-templated constructor.

    > Q4. If I want to make a template class, do I need to provide both copy
    > constructor?
    > If not, which is better? And why?


    Unless you have the situation where you want a Foo<T> to be copy-
    constructible from Foo<S>, you should just go with the first.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Sep 26, 2010
    #2
    1. Advertising

  3. cinsk

    cinsk Guest

    On Sep 27, 12:30 am, Kai-Uwe Bux <> wrote:
    > cinsk wrote:
    > > hi.

    >
    > > I just read the definition of the std::pair in <utility>.  std::pair
    > > has following two copy constructors:

    >
    > > template <class T1, class T2>
    > > struct pair {

    >
    > >   pair::pair(const pair &);

    >
    > >   template<class U1, class U2> pair::pair(const pair<U1, U2> &);
    > >   ...
    > > };

    >
    > > The definition of both copy constructor looks same in my gentoo Linux/
    > > gcc 4.4.3.

    >
    > > Although I'm not good at template, both copy constructors look same to
    > > me.

    >
    > > Q1. What is the purpose of the second copy constructor?
    > >       Could you give me some short example code that actually calls
    > > the second copy constructor?

    >
    > It allows to copy construct a std::pair<double,double> from a
    > std::pair<int,int>.
    >
    > > Q2. What happen if the second copy construct is missing?

    >
    > The above would not be possible
    >
    > > Q3. How can the compiler determine which copy constructor is used?
    > >       In my poor understanding, it looks like that compile would
    > > complain for the ambiguity.

    >
    > The ambiguity you worry about arises as copy-constructing std::pair<int,int>
    > from std::pair<int,int> matches both. That is true. In that case, overload
    > resolution kicks in. In this case, the ambiguity is resolved in favor of the
    > non-templated constructor.
    >
    > > Q4. If I want to make a template class, do I need to provide both copy
    > > constructor?
    > >       If not, which is better? And why?

    >
    > Unless you have the situation where you want a Foo<T> to be copy-
    > constructible from Foo<S>, you should just go with the first.
    >
    > Best
    >
    > Kai-Uwe Bux


    Thank you for the kind answers!

    Regards,
    cinsk, Sep 26, 2010
    #3
  4. Kai-Uwe Bux <> wrote:
    >> pair::pair(const pair &);
    >>
    >> template<class U1, class U2> pair::pair(const pair<U1, U2> &);

    >
    > It allows to copy construct a std::pair<double,double> from a
    > std::pair<int,int>.


    Of course this could raise the question of why that *first* copy
    constructor is necessary at all, then (because wouldn't the second
    one cover also the case where the types are the same)?

    IIRC there was some kind of special rule about constructors and
    templates in play here. Could someone refresh my memory?
    Juha Nieminen, Sep 26, 2010
    #4
  5. cinsk

    Bo Persson Guest

    Juha Nieminen wrote:
    > Kai-Uwe Bux <> wrote:
    >>> pair::pair(const pair &);
    >>>
    >>> template<class U1, class U2> pair::pair(const pair<U1, U2> &);

    >>
    >> It allows to copy construct a std::pair<double,double> from a
    >> std::pair<int,int>.

    >
    > Of course this could raise the question of why that *first* copy
    > constructor is necessary at all, then (because wouldn't the second
    > one cover also the case where the types are the same)?
    >
    > IIRC there was some kind of special rule about constructors and
    > templates in play here. Could someone refresh my memory?


    Yes, the first constructor is a copy constructor, the second one is a
    converting constructor.

    §12.8 says that a template is never a copy constructor.


    Bo Persson
    Bo Persson, Sep 26, 2010
    #5
  6. Bo Persson <> wrote:
    > §12.8 says that a template is never a copy constructor.


    What is the rationale for that rule?
    Juha Nieminen, Sep 26, 2010
    #6
  7. On Sep 27, 12:24 am, Juha Nieminen <> wrote:
    > Bo Persson <> wrote:
    > > §12.8 says that a template is never a copy constructor.

    >
    >   What is the rationale for that rule?


    I am not an expert, but I'll give it a try. Maybe because the copy
    constructor is ALWAYS declared, and the declaration is not a template
    one?
    Armen Tsirunyan, Sep 26, 2010
    #7
  8. Juha Nieminen wrote:

    > Bo Persson <> wrote:
    >> §12.8 says that a template is never a copy constructor.

    >
    > What is the rationale for that rule?


    In C++03, there appears to be no way to declare a copy constructor even if
    that rule were absent. This is because you need the first parameter to be
    based on the current class type. But if it includes template parameters of
    itself, this can never be the case:

    struct A {
    template<typename T>
    A(... /* where to put T!? */);
    };

    In C++0x this is possible by just using default arguments

    struct A {
    template<typename T = int>
    A(A const&);
    };

    So the actual reason might be that a template is not really a function. It's
    a template that first need to be instantiated.

    There is another rule that a template cannot be used to instantiate a copy
    constructor. But that rule's history is quite amusing. I have seen people in
    here argue about it and its desired meaning, but it appears it's very
    simple: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1080 .
    Johannes Schaub (litb), Sep 27, 2010
    #8
  9. cinsk

    James Kanze Guest

    On Sep 27, 3:00 pm, "Johannes Schaub (litb)" <>
    wrote:
    > Juha Nieminen wrote:
    > > Bo Persson <> wrote:
    > >> §12.8 says that a template is never a copy constructor.


    > > What is the rationale for that rule?


    > In C++03, there appears to be no way to declare a copy
    > constructor even if that rule were absent. This is because you
    > need the first parameter to be based on the current class
    > type. But if it includes template parameters of itself, this
    > can never be the case:


    > struct A {
    > template<typename T>
    > A(... /* where to put T!? */);
    > };


    > In C++0x this is possible by just using default arguments


    > struct A {
    > template<typename T = int>
    > A(A const&);
    > };


    > So the actual reason might be that a template is not really
    > a function. It's a template that first need to be
    > instantiated.


    > There is another rule that a template cannot be used to
    > instantiate a copy constructor. But that rule's history is
    > quite amusing. I have seen people in here argue about it and
    > its desired meaning, but it appears it's very
    > simple:http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1080.


    It's not that simple, because when copying an object, normal
    overload resolution is done. The "copy constructor" has no
    priviledged role. What is important is that a template function
    cannot ever be a copy constructor, which means that it won't
    prevent the compiler from generating one, e.g.:

    struct A
    {
    template<typename T>
    A(T const& other) { std::cout << "Copying" << std::endl; }
    };

    int
    main()
    {
    A a;
    A b(a);
    return 0;
    }

    will output nothing (since the compiler generated copy
    constructor is an equally good match as the template, and when
    two functions are otherwise equally good matches, the
    non-template wins). Drop the const in the signature of the
    constructor template, and the template will win, since it is
    a better match. (The compiler generated copy constructor will
    still be generated, and be used when copying a temporary.)

    Of course, if the compiler generated copy constructor doesn't do
    what you want, you'll have to define one in addition to the
    templated one, or you'll spend a lot of time tracking down
    obscure errors.

    --
    James Kanze
    James Kanze, Sep 27, 2010
    #9
  10. James Kanze wrote:

    > On Sep 27, 3:00 pm, "Johannes Schaub (litb)" <>
    > wrote:
    >> Juha Nieminen wrote:
    >> > Bo Persson <> wrote:
    >> >> §12.8 says that a template is never a copy constructor.

    >
    >> > What is the rationale for that rule?

    >
    >> In C++03, there appears to be no way to declare a copy
    >> constructor even if that rule were absent. This is because you
    >> need the first parameter to be based on the current class
    >> type. But if it includes template parameters of itself, this
    >> can never be the case:

    >
    >> struct A {
    >> template<typename T>
    >> A(... /* where to put T!? */);
    >> };

    >
    >> In C++0x this is possible by just using default arguments

    >
    >> struct A {
    >> template<typename T = int>
    >> A(A const&);
    >> };

    >
    >> So the actual reason might be that a template is not really
    >> a function. It's a template that first need to be
    >> instantiated.

    >
    >> There is another rule that a template cannot be used to
    >> instantiate a copy constructor. But that rule's history is
    >> quite amusing. I have seen people in here argue about it and
    >> its desired meaning, but it appears it's very
    >> simple:http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1080.

    >
    > It's not that simple, because when copying an object, normal
    > overload resolution is done. The "copy constructor" has no
    > priviledged role. What is important is that a template function
    > cannot ever be a copy constructor, which means that it won't
    > prevent the compiler from generating one, e.g.:
    >


    That's clear anyway because only a non-template constructor can be a copy
    constructor. What I meant is that people disagreed on what that statement
    means to never instantiate a constructor to do the copy

    - Templates are just ignored when doing overload resolution when copying a
    class object of type A to another object of type A
    - Templates are considered, but if an instantiation is needed the program
    either needs to explicitly instantiate the constructor or explicitly
    specialize it to provide a suitable specialization.
    - Templates are considered, but overload resolution ignores any candidates
    for which argument deduction yields a parameter list with "cv T" as type.

    The issue was further confused by a footnote that explicitly allowed a
    template constructor to be used to copy the object in C++03, and that note
    was removed from the C++0x draft. And now they get to it again and see they
    shouldn't had removed that footnote.
    Johannes Schaub (litb), Sep 27, 2010
    #10
  11. cinsk

    James Kanze Guest

    On Sep 27, 7:20 pm, "Johannes Schaub (litb)" <>
    wrote:
    > James Kanze wrote:
    > > On Sep 27, 3:00 pm, "Johannes Schaub (litb)" <>
    > > wrote:
    > >> There is another rule that a template cannot be used to
    > >> instantiate a copy constructor. But that rule's history is
    > >> quite amusing. I have seen people in here argue about it and
    > >> its desired meaning, but it appears it's very
    > >> simple:http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1080.


    > > It's not that simple, because when copying an object, normal
    > > overload resolution is done. The "copy constructor" has no
    > > priviledged role. What is important is that a template function
    > > cannot ever be a copy constructor, which means that it won't
    > > prevent the compiler from generating one, e.g.:


    > That's clear anyway because only a non-template constructor
    > can be a copy constructor. What I meant is that people
    > disagreed on what that statement means to never instantiate
    > a constructor to do the copy


    > - Templates are just ignored when doing overload resolution
    > when copying a class object of type A to another object of
    > type A
    > - Templates are considered, but if an instantiation is needed
    > the program either needs to explicitly instantiate the
    > constructor or explicitly specialize it to provide a suitable
    > specialization.
    > - Templates are considered, but overload resolution ignores
    > any candidates for which argument deduction yields a parameter
    > list with "cv T" as type.


    There's no disagreement possible. The "copy constructor" is
    special only in that it will be supplied by the compiler if the
    user doesn't supply one. When copying, it has no special role.
    Normal overload resolution takes place.

    > The issue was further confused by a footnote that explicitly
    > allowed a template constructor to be used to copy the object
    > in C++03, and that note was removed from the C++0x draft. And
    > now they get to it again and see they shouldn't had removed
    > that footnote.


    Footnotes aren't nominative. There was never any ambiguity in
    the nominative text (§8.5/14): "The applicable constructors are
    enumerated (13.3.1.3), and the best one is chosen through
    overload resolution (13.3)." I don't think there is any
    ambiguity there.

    --
    James Kanze
    James Kanze, Sep 28, 2010
    #11
  12. "Johannes Schaub (litb)" <> wrote:
    > Juha Nieminen wrote:
    >
    >> Bo Persson <> wrote:
    >>> §12.8 says that a template is never a copy constructor.

    >>
    >> What is the rationale for that rule?

    >
    > In C++03, there appears to be no way to declare a copy constructor even if
    > that rule were absent. This is because you need the first parameter to be
    > based on the current class type. But if it includes template parameters of
    > itself, this can never be the case:
    >
    > struct A {
    > template<typename T>
    > A(... /* where to put T!? */);
    > };


    I don't really understand.

    struct A
    {
    template<typename T>
    A(const T&);
    };

    When a copy constructor is invoked, it would match that templated
    constructor above (because T = A, and hence it becomes A(const A&))
    Juha Nieminen, Sep 28, 2010
    #12
  13. cinsk

    James Kanze Guest

    On Sep 28, 11:37 am, Juha Nieminen <> wrote:
    > "Johannes Schaub (litb)" <> wrote:
    > > Juha Nieminen wrote:


    [...]
    > When a copy constructor is invoked, it would match that templated
    > constructor above (because T = A, and hence it becomes A(const A&))


    Just to keep things straight: there is no construct in the C++
    language which invokes a "copy constructor". There are
    constructs which invoke constructors, but they all do classical
    overload resolution, in which a copy constructor is just another
    constructor.

    The only time it makes any sense to speak about a copy
    constructor, as opposed to a constructor in general, is when
    discussion whether the compiler will generate one automatically.
    (If it does, of course, this becomes just one more constructor
    to consider in overload resolution.)

    --
    James Kanze
    James Kanze, Sep 28, 2010
    #13
  14. cinsk

    Bo Persson Guest

    Juha Nieminen wrote:
    > "Johannes Schaub (litb)" <> wrote:
    >> Juha Nieminen wrote:
    >>
    >>> Bo Persson <> wrote:
    >>>> §12.8 says that a template is never a copy constructor.
    >>>
    >>> What is the rationale for that rule?

    >>
    >> In C++03, there appears to be no way to declare a copy constructor
    >> even if that rule were absent. This is because you need the first
    >> parameter to be based on the current class type. But if it
    >> includes template parameters of itself, this can never be the case:
    >>
    >> struct A {
    >> template<typename T>
    >> A(... /* where to put T!? */);
    >> };

    >
    > I don't really understand.
    >
    > struct A
    > {
    > template<typename T>
    > A(const T&);
    > };
    >
    > When a copy constructor is invoked, it would match that templated
    > constructor above (because T = A, and hence it becomes A(const A&))


    But it doesn't, as the implicitly defined A(const A&) takes
    precendence. It is a better match for the overload resolution.


    Bo Persson
    Bo Persson, Sep 28, 2010
    #14
  15. James Kanze <> wrote:
    > The only time it makes any sense to speak about a copy
    > constructor, as opposed to a constructor in general, is when
    > discussion whether the compiler will generate one automatically.
    > (If it does, of course, this becomes just one more constructor
    > to consider in overload resolution.)


    What happens in C++0x if you explicitly disable the copy constructor,
    and then there's a templated constructor which would match? Does the
    disabling take precedence?
    Juha Nieminen, Sep 29, 2010
    #15
  16. cinsk

    James Kanze Guest

    On Sep 29, 2:56 pm, Juha Nieminen <> wrote:
    > James Kanze <> wrote:
    > > The only time it makes any sense to speak about a copy
    > > constructor, as opposed to a constructor in general, is when
    > > discussion whether the compiler will generate one automatically.
    > > (If it does, of course, this becomes just one more constructor
    > > to consider in overload resolution.)


    > What happens in C++0x if you explicitly disable the copy
    > constructor, and then there's a templated constructor
    > which would match? Does the disabling take precedence?


    Good question. If I understand it correctly, a "deleted"
    function is actually defined, so would be considered in
    overload resolution. Then, if overload resolution chose it,
    you would get an error. This could lead to some interesting
    situations:

    struct C
    {
    C(C&) = delete;
    template<typename T>
    C(T const&);
    };

    With such a class, you could copy rvalues and const lvalues,
    but not non-const lvalues (since the deleted function would
    be a better match than the template).

    --
    James Kanze
    James Kanze, Sep 29, 2010
    #16
  17. Juha Nieminen wrote:

    > "Johannes Schaub (litb)" <> wrote:
    >> Juha Nieminen wrote:
    >>
    >>> Bo Persson <> wrote:
    >>>> §12.8 says that a template is never a copy constructor.
    >>>
    >>> What is the rationale for that rule?

    >>
    >> In C++03, there appears to be no way to declare a copy constructor even
    >> if that rule were absent. This is because you need the first parameter to
    >> be based on the current class type. But if it includes template
    >> parameters of itself, this can never be the case:
    >>
    >> struct A {
    >> template<typename T>
    >> A(... /* where to put T!? */);
    >> };

    >
    > I don't really understand.
    >
    > struct A
    > {
    > template<typename T>
    > A(const T&);
    > };
    >


    No, that template is not a copy constructor because the parameter is of type
    "const T&", not "const A&".
    Johannes Schaub (litb), Oct 8, 2010
    #17
  18. cinsk

    James Kanze Guest

    On Oct 8, 11:14 pm, "Johannes Schaub (litb)" <>
    wrote:
    > Juha Nieminen wrote:
    > > "Johannes Schaub (litb)" <> wrote:
    > >> Juha Nieminen wrote:


    > >>> Bo Persson <> wrote:
    > >>>> §12.8 says that a template is never a copy constructor.


    > >>> What is the rationale for that rule?


    > >> In C++03, there appears to be no way to declare a copy
    > >> constructor even if that rule were absent. This is because
    > >> you need the first parameter to be based on the current
    > >> class type. But if it includes template parameters of
    > >> itself, this can never be the case:


    > >> struct A {
    > >> template<typename T>
    > >> A(... /* where to put T!? */);
    > >> };


    > > I don't really understand.


    > > struct A
    > > {
    > > template<typename T>
    > > A(const T&);
    > > };


    > No, that template is not a copy constructor because the
    > parameter is of type "const T&", not "const A&".


    No. An instantiation of that template (even for A) is not a copy
    constructor because the standard says that instantiations of
    templates are never copy constructors. Without this special
    rule, it would be a copy constructor, because when instantiated
    with A, its parameter has type A const&.

    --
    James Kanze
    James Kanze, Oct 9, 2010
    #18
  19. James Kanze wrote:

    > On Oct 8, 11:14 pm, "Johannes Schaub (litb)" <>
    > wrote:
    >> Juha Nieminen wrote:
    >> > "Johannes Schaub (litb)" <> wrote:
    >> >> Juha Nieminen wrote:

    >
    >> >>> Bo Persson <> wrote:
    >> >>>> §12.8 says that a template is never a copy constructor.

    >
    >> >>> What is the rationale for that rule?

    >
    >> >> In C++03, there appears to be no way to declare a copy
    >> >> constructor even if that rule were absent. This is because
    >> >> you need the first parameter to be based on the current
    >> >> class type. But if it includes template parameters of
    >> >> itself, this can never be the case:

    >
    >> >> struct A {
    >> >> template<typename T>
    >> >> A(... /* where to put T!? */);
    >> >> };

    >
    >> > I don't really understand.

    >
    >> > struct A
    >> > {
    >> > template<typename T>
    >> > A(const T&);
    >> > };

    >
    >> No, that template is not a copy constructor because the
    >> parameter is of type "const T&", not "const A&".

    >
    > No. An instantiation of that template (even for A) is not a copy
    > constructor because the standard says that instantiations of
    > templates are never copy constructors. Without this special
    > rule, it would be a copy constructor, because when instantiated
    > with A, its parameter has type A const&.
    >


    It says that a constructor of class X whose first parameter is of type "cv
    X&" and either there are no other parameters or all other parameters have
    default arguments, is a copy constructor. This does not apply to the above
    template, and so it is *not* a copy constructor.

    If you read what I wrote carefully, you will find I have not said anything
    about an instantiated specialization of it being a copy constructor or not.
    Please read more careful before disagreeing.
    Johannes Schaub (litb), Oct 9, 2010
    #19
  20. In article <i8pkvg$20r$03$-online.com>, Johannes Schaub (litb)
    says...
    > It says that a constructor of class X whose first parameter is of type "cv
    > X&" and either there are no other parameters or all other parameters have
    > default arguments, is a copy constructor. This does not apply to the above
    > template, and so it is *not* a copy constructor.
    >


    I'm agree with James. It's not a copy constructor because the draft says
    "A non-template constructor for class X is a copy constructor if ..."
    and not only "its first parameter is of type X&,...".

    If it was just "its first parameter is of type X&,...", the result of

    struct A { template<class T> A(T&){std::cout << 0} };
    int main() { A a; A b(a); return 0; }

    would be "0", because the template constructor A<A>(A&) is a constructor
    and is first parameter is of type A&. And the result isn't "0".

    Even if it isn't a "strict" copy constructor, it's called "generalized
    copy constructor" by some programmers (like Meyers, cf Eff++ Item 45).
    Blanchet Florian, Oct 9, 2010
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. VisionSet
    Replies:
    8
    Views:
    4,892
    Tris Orendorff
    Apr 29, 2004
  2. Aire
    Replies:
    3
    Views:
    463
    Mike Wahler
    Jan 25, 2004
  3. sahpathi
    Replies:
    4
    Views:
    314
    sahpathi
    Jun 12, 2006
  4. ali
    Replies:
    4
    Views:
    572
    David Harmon
    Mar 5, 2007
  5. Generic Usenet Account
    Replies:
    10
    Views:
    2,218
Loading...

Share This Page