template copy constructor vs normal copy constructor

J

Johannes Schaub (litb)

Blanchet said:
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".

I keep disagreeing This is allegedly forbidden (by the interpretation of
some people) by another paragraph, namely 12.8/p3 "A member function
template is never instantiated to perform the copy of a class object to an
object of its class type." (See the other post of me where I link to an
issue report about the interpretation of this).

12.8/p2 has nothing to do with it. The stuff you quote from p2 says that a
*non-template* can be a copy constructor - in other words a template cannot
be a copy constructor. A function instantiated from a template is not a
template. So it does entirely not apply, see below.

In addition, nothing says that only copy constructors are allowed to copy an
object. So even if it were like you are saying and "A non-template ..."
makes also the specialization non-copy constructors, that wouldn't change
anything with regard to your example above.

What it makes sure is that the following template declaration does not
inhibit the implicit declaration of a copy constructor

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

If we take out "A non-template" then in C++0x the above will not have an
implicitly declared copy-constructor anymore, because the template will be a
copy constructor. Now I was stating such code is impossible in C++03 anyway
because in C++03 you must arrange for "T" to be deduced from the arguments,
and then you cannot satisfy the conditions for copy constructors anymoe.

Also, there is a destinction between "non-template" and "non-template
function":

- non-template: Anything that is not a template.
- non-template function: Anything that is a function, but is not a function
template specialization.

The first is a natural term which just says "not a template". I can't find
any other non-natural usage of it in the IS. But the latter has special
meaning in the IS: And it's used as if it's the negation of the pre-C++03
"template function" term, and as such excludes function template
specializations as opposed to "non-template".

12.8/p2 says "non-template constructor" so it means:

- Any constructor that is not a template

This includes constructors instantiated from templates, as opposed to
excluding them.
 
B

Blanchet Florian

Leigh said:
The result is "0" on VC++ and g++. If it was A(const T&) the result
wouldn't be "0".

/Leigh


Yes, I forgot a const, in "generalized copy constructor" or in
declaration of a. (I would just shows that the default copy constructor
is generated by the compiler)

PS: I forgot a default constructor too.
 
J

Johannes Schaub (litb)

Johannes said:
I keep disagreeing This is allegedly forbidden (by the interpretation of
some people) by another paragraph, namely 12.8/p3 "A member function
template is never instantiated to perform the copy of a class object to an
object of its class type." (See the other post of me where I link to an
issue report about the interpretation of this).

12.8/p2 has nothing to do with it. The stuff you quote from p2 says that a
*non-template* can be a copy constructor - in other words a template
cannot be a copy constructor. A function instantiated from a template is
not a template. So it does entirely not apply, see below.

In addition, nothing says that only copy constructors are allowed to copy
an object. So even if it were like you are saying and "A non-template ..."
makes also the specialization non-copy constructors, that wouldn't change
anything with regard to your example above.

What it makes sure is that the following template declaration does not
inhibit the implicit declaration of a copy constructor

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

If we take out "A non-template" then in C++0x the above will not have an
implicitly declared copy-constructor anymore, because the template will be
a copy constructor. Now I was stating such code is impossible in C++03
anyway because in C++03 you must arrange for "T" to be deduced from the
arguments, and then you cannot satisfy the conditions for copy
constructors anymoe.

I just see that I miss some very important insight throughout the whole
discussion. The following *is* valid C++03:

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

So, if "A non-template" would be missing, then this would inhibit the
implicitly declared copy constructor too, and the following will be ill-
formed:

A a;
A b = a; // no matching constructor!

So please take this into account when answering. I was overlooking this and
thought "If it can't be deduced, it's illegal" but that of course is not
true at all.
 
B

Blanchet Florian

Johannes Schaub (litb) said:
I keep disagreeing This is allegedly forbidden (by the interpretation of
some people) by another paragraph, namely 12.8/p3 "A member function
template is never instantiated to perform the copy of a class object to an
object of its class type." (See the other post of me where I link to an
issue report about the interpretation of this).

12.8/p3 is about move-constructor in n3126, and I think gcc repect these
points of the draft. (So "A member function template is never
instantiated to perform the copy of a class object to an object of its
class type." is not true now).
12.8/p2 has nothing to do with it. The stuff you quote from p2 says that a
*non-template* can be a copy constructor - in other words a template cannot
be a copy constructor. A function instantiated from a template is not a
template. So it does entirely not apply, see below.

In addition, nothing says that only copy constructors are allowed to copy an
object. So even if it were like you are saying and "A non-template ..."
makes also the specialization non-copy constructors, that wouldn't change
anything with regard to your example above.

Yes, I forgot a const to force to call default copy constructor.
What it makes sure is that the following template declaration does not
inhibit the implicit declaration of a copy constructor

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

This includes constructors instantiated from templates, as opposed to
excluding them.

So, what is exclude ?
 
J

Johannes Schaub (litb)

Blanchet said:
12.8/p3 is about move-constructor in n3126, and I think gcc repect these
points of the draft. (So "A member function template is never
instantiated to perform the copy of a class object to an object of its
class type." is not true now).

I don't understand this.
If I'm based on Comeau C++ Template FAQ, A<A>(A&) (or A<A>(const A&)),
is a template function, so is not a non-template function.

A constructor is not necessarily a function. It can also be a template. But
you take the term "non-template constructor" and replace it by "non-template
function". These two are not equivalent.

In the IS, it's all about terms and the order they are presented in a
sentence. For example, "int &r;" is an object declaration. But it is not the
declaration of an object.

If "non-template constructor" is intended to mean something else than
"constructor that is not a template", I suggest the wording to be changed to
indicate the real intent. Or to at least put an explanatory note.
I'm agrre, because A<T>(A const&) is a template function, so the
compiler have to make a default copy-constructor.

It has nothing to do with template functions (these are called "function
template specializations" in C++03 onwards. The term "template function" is
not used anymore). The reason the above still declares an implicit copy
constructor is that our declared A::A is a template, and templates aren't
copy constructors.

You cannot explicitly declare a function template specialization in the
class definition. The condition for implicit declaration of a copy
constructor is that the class definition does not explicitly declare a copy
constructor, though.
So, what is exclude ?

I don't understand.
 
B

Blanchet Florian

Johannes Schaub (litb) said:
A constructor is not necessarily a function. It can also be a template. But
you take the term "non-template constructor" and replace it by "non-template
function". These two are not equivalent.

In the IS, it's all about terms and the order they are presented in a
sentence. For example, "int &r;" is an object declaration. But it is not the
declaration of an object.

If "non-template constructor" is intended to mean something else than
"constructor that is not a template", I suggest the wording to be changed to
indicate the real intent. Or to at least put an explanatory note.

I know that terms are very important in the IS, but perhap's I
misunderstand the template terms. I'll try to well understand your
messages.

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

template<>
A::A<char>(const A&) {std::cout << 0;}

int main()
{
A a;
A b = a;
system("PAUSE"); return 0;
}

So, (correct if I say wrong things), in this code, A::A<char> is a
template constructor ? And its first parameter is of type const A&, so
it's a copy constructor ? But, when I try this code with gcc there is no
output. It's because this template constructor is declared (and define)
outside A ?
 
J

Johannes Schaub (litb)

Blanchet said:
I know that terms are very important in the IS, but perhap's I
misunderstand the template terms. I'll try to well understand your
messages.

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

template<>
A::A<char>(const A&) {std::cout << 0;}

int main()
{
A a;
A b = a;
system("PAUSE"); return 0;
}

So, (correct if I say wrong things), in this code, A::A<char> is a
template constructor ?

It is

- A function template specialization. We could call it a template function
since that's the term used by ARM and still by some, but not really by C++03
anymore.
- Not a function template. Therefor, from what the IS says I conclude it is
a "non-template constructor". It's a function, not a template.

The second A::A you declared is

- Not a function template specialization
- A function template. Therefor, from what the IS says I conclude it is a
"non-template constructor". It's a function, not a template.

I have to say I'm not quite sure about the exact meaning of "template
constructor" anymore. A::A<char> definitely is not a template. But likewise
is a "template function" not a template. Still "template" appears in the
term of "template function", but only to say that the function was generated
from / explicitly specified for a template.

I wouldn't want to bet on the exact meaning of "template constructor". I
just think that the "obvious" meaning is "A constructor that is not a
template".
And its first parameter is of type const A&, so
it's a copy constructor ?

But, when I try this code with gcc there is no
output. It's because this template constructor is declared (and define)
outside A ?

No, it is simply because the template cannot be called. How should it deduce
the template parameter of it? You have to give the parameter a default
argument (C++0x) to be able to call it.
 
J

James Kanze

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.

The above template isn't even a constructor until its
instantiated. Use a little common sense. The class above has a
constructor, defined by the template, which has a single
parameter of type A const&. Without the special language
excluding templates, it would be 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.

I'm not disagreeing, the standard is.
 
J

James Kanze

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".

It should be. The fact that the template is not a copy
constructor means that the compiler will generate one. With the
signature (here): A(T const&). But the template function
remains a better match if the object is a non-const lvalue, as
is the case here, so it gets chosen over the compiler generated
copy constructor.

If the template had the signature A(T const&), this would not be
the case, since both it and the compiler generated constructors
would be equally good matches, and when all other things are
equal, a non-template function wins over a template function.
Even if it isn't a "strict" copy constructor, it's called
"generalized copy constructor" by some programmers (like
Meyers, cf Eff++ Item 45).

It's partially a question of context. In the context of the
standard, the presence of a user defined "copy constructor"
prevents the compiler from generating a default copy
constructor. And that is all "copy constructor" means in the
standard. There is no preference for a copy constructor when
copying, for example; normal overload resolution applies. In
everyday speach, however, it's more or less normal to consider
any constructor which "copies", or which is used to copy, a copy
constructor. This is (I'm fairly sure) what Meyers means by
"generalized copy constructor".
 
J

Johannes Schaub (litb)

James said:
The above template isn't even a constructor until its
instantiated. Use a little common sense. The class above has a
constructor, defined by the template, which has a single
parameter of type A const&. Without the special language
excluding templates, it would be a copy constructor.

Now you are contradicting yourself: "The above template isn't even a
constructor until its [sic] instantiated." <-> "The class above has a
constructor, defined by the template, [...]".

"The class above has a constructor, defined by the template, which has a
single parameter of type A const&." -> No, the parameter of that function
template is of type "T const&". The types "T const&" and "A const&" are
different. Only the function generated from the template when it is
instantiated has the type "A const&". But such a function is a non-template.
Still, such a function is not a "non-template function", because of the
special meaning of "non-template function" in the Standard, kept over from
the ARM.

In the above, there wasn't even any function generated. There was just the
function template with parameter type "const T&". Where do you see the copy
constructor?

"The above template isn't even a constructor until its [sic] instantiated."
-> Not true. It is a template constructor / constructor template / templated
constructor / whatever you want to call it. When it is instantiated, the
result is a non-template. It's a function. For an example where it matters:
The spec says "A declaration of a constructor for a class X is ill-formed if
its first parameter is of type (optionally cv-qualified) X and either there
are no other parameters or else all other parameters have default
arguments.", and consequently, comeau/gcc/clang reject the following code

struct A {
template<typename T>
A(A); // ill-formed constructor
};

No instantiation what-so-ever is needed.
 
J

James Kanze

I keep disagreeing This is allegedly forbidden (by the
interpretation of some people) by another paragraph, namely
12.8/p3 "A member function template is never instantiated to
perform the copy of a class object to an object of its class
type." (See the other post of me where I link to an issue
report about the interpretation of this).

You're quoting out of context there. Paragraph 12.8/p3 is
talking about constructors taking the class (and not a reference
to the class) as a parameter. It's not very well worded, but I
think what it's trying to say is that:

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

will never be instantiated with T == A. (But I need to read the
entire section, as well as paragraph 8.5/14, to understand this,
because it sure isn't what I'd understand reading the paragraph
in isolation. It is, in fact, misleading enough that I think a
DR is in order.)
12.8/p2 has nothing to do with it.

Paragraph 12.8 *is* the definition of a copy constructor.
(Notice that the word copy is in italics.)
The stuff you quote from p2 says that a *non-template* can be
a copy constructor - in other words a template cannot be a
copy constructor. A function instantiated from a template is
not a template. So it does entirely not apply, see below.

Since when does "is" mean "can" in English. The sentence is
quite clear: "A non-template constructor for class X is a copy
constructor if[...]". Not can be, or might be, or anything
else. This is where the standard defines copy constructor.
In addition, nothing says that only copy constructors are
allowed to copy an object.

Nobody is arguing that. Although there is some very strange
text in paragraph 8, which suggests that the following might
hold:

// No const on the template function.
struct A { template<typename T> A(T&) { cout << 0; } };
// Now a class with a copy-ctor which takes a non-const
// reference.
struct B { B(B&); };

// Inheriting from B means that the compiler generated
// copy-ctor will have the signature C(C&), without a
// const.
struct C : A, B {};

int main()
{
A a;
A b(a); // Outputs 0.
C c;
C d(c); // Doesn't output anything.
}

Paragraph 8 says that if the subobject is of class type (the
case here), the copy constructor will be used. Since the
template function clearly is not a copy constructor, and the
class has a copy constructor (provided by the compiler), that
copy constructor will be used, even though the template
constructor is a better match.

I'm not sure that this difference is intentional. Again, it's
possible that a DR is in order.
So even if it were like you are
saying and "A non-template ..." makes also the specialization
non-copy constructors, that wouldn't change anything with
regard to your example above.
What it makes sure is that the following template declaration
does not inhibit the implicit declaration of a copy
constructor

Yes, and since that is the effect (and the only effect) of a
user declared copy constructor, that's the issue.
 
J

James Kanze

Johannes Schaub (litb) wrote:

[...]
I just see that I miss some very important insight throughout the whole
discussion. The following *is* valid C++03:
struct A {
template<typename T>
A(A const&);
};
So, if "A non-template" would be missing, then this would
inhibit the implicitly declared copy constructor too, and the
following will be ill- formed:
A a;
A b = a; // no matching constructor!

Why would that be ill formed? There is a matching constructor.
Consider, for example:

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

A const a;
A b(a);

If the template were considered a copy constructor, this would
be ill formed (since there would be no matching constructor).
But there would be no problem with your example, since an
instantiation of the template would be used to copy.
 
J

James Kanze

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

Totally unrelated to the discussion in process, but...

A default template-argument shall not be specified in a
function template declaration or a function template
definition, nor in the template-parameter-list of the
definition of a member of a class template.[§14.1/9]

Just ignore any arguments based on this.
 
J

James Kanze

Blanchet said:
I don't understand this.

Blanchet is referring to a draft of the future standard. Which
might be completely different from the current standard.
A constructor is not necessarily a function.

That's why the section defining constructors is in the section
"Special Member Functions".

Actually, I'm beginning to think that section 12 needs to be
completely rewritten. Paragraph one clearly states that the
special member functions are those that can be implicitly
declared or defined by the compiler. Paragraph 2 seems to apply
to all constructors (and not just default and copy
constructors), and 12.1 starts by defining a constructor, in
general. Without really being clear what they are.

Globally, however, I think the only reasonable interpretation is
that constructors are functions, and...
It can also be a template.

It is the instantiation of the template which is a constructor.

But the standard is hardly clear about this.
But you take the term "non-template constructor" and
replace it by "non-template function". These two are not
equivalent.

So where is "non-template constructor" defined?
In the IS, it's all about terms and the order they are
presented in a sentence. For example, "int &r;" is an object
declaration. But it is not the declaration of an object.

What makes you think it's an object declaration?
 
J

Johannes Schaub (litb)

James said:
Johannes Schaub (litb) wrote:
[...]
I just see that I miss some very important insight throughout the whole
discussion. The following *is* valid C++03:
struct A {
template<typename T>
A(A const&);
};
So, if "A non-template" would be missing, then this would
inhibit the implicitly declared copy constructor too, and the
following will be ill- formed:
A a;
A b = a; // no matching constructor!

Why would that be ill formed? There is a matching constructor.
Consider, for example:

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

A const a;
A b(a);

If the template were considered a copy constructor, this would
be ill formed (since there would be no matching constructor).
But there would be no problem with your example, since an
instantiation of the template would be used to copy.

Yes, and I'm now ignoring your posts, since you are obviously not interested
in a real discussion.

I'm returning to you if you start actually trying to read and not just
answering for the lulz. Sorry, that's how it looks to me.
 
J

James Kanze

James said:
Johannes Schaub (litb) wrote:
[...]
I just see that I miss some very important insight
throughout the whole discussion. The following *is* valid
C++03:
struct A {
template<typename T>
A(A const&);
};
So, if "A non-template" would be missing, then this would
inhibit the implicitly declared copy constructor too, and the
following will be ill- formed:
A a;
A b = a; // no matching constructor!
Why would that be ill formed? There is a matching constructor.
Consider, for example:
struct A { template<typename T> A(A&); };
A const a;
A b(a);
If the template were considered a copy constructor, this would
be ill formed (since there would be no matching constructor).
But there would be no problem with your example, since an
instantiation of the template would be used to copy.
Yes, and I'm now ignoring your posts, since you are obviously
not interested in a real discussion.

In other words, you have no arguments, but rather than admit you
were wrong, you'll go off in a corner and pout.

So be it.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top