Templates and Copy Constructors. Again.

M

Matt Bitten

Hi, all. I have the same old problem about templates and
copy constructors. I know this has been addressed hundreds
of times, but despite perusing many old postings, and The
Standard as well, I'm still feeling confused.

Suppose I have a class template:

template <typename T>
class Foo {

I think I declare the copy cconstructor as follows:

Foo(const Foo & another);

And if I do not declare it that way, the compiler writes a
copy constructor for me. Is that right?

Now, if I understand correctly, "Foo" is not a type, but a
template. So what does it mean that this function I'm
declaring takes a const reference to a Foo, when Foo is not
a type? Is it that "Foo", inside the class definition, is
a synonym for the type of the current object?

If so, does that mean I can do this (inside the class
definition):

int bar(Foo x);

Can I declare the copy constructor differently? In
particular, are any of the following, written inside the
class definition, equivalent to the above:

Foo(const Foo<T> & another);
Foo<T>(const Foo & another);
Foo<T>(const Foo<T> & another);

Now say I want to implement my copy constructor outside the
body of the class definition. How do I write the definition
of the function?

Thanks for any help. I know that a reasonable answer to
some of my questions above is "Try it out, you ninny!"
However, I want to write standard-conforming code, and I am
worried that my compiler and The Standard might not agree
on some points.
 
V

Victor Bazarov

Matt Bitten said:
[...]
Suppose I have a class template:

template <typename T>
class Foo {

I think I declare the copy cconstructor as follows:

Foo(const Foo & another);

And if I do not declare it that way, the compiler writes a
copy constructor for me. Is that right?
Yes.

Now, if I understand correctly, "Foo" is not a type, but a
template. So what does it mean that this function I'm
declaring takes a const reference to a Foo, when Foo is not
a type? Is it that "Foo", inside the class definition, is
a synonym for the type of the current object?

'Foo' outside the template is a template-id. Inside the template
definition, 'Foo' by itself is "the same type as the one being
instantiated". IOW, if you write Foo<int> somewhere, and then
make it so its copy c-tor is used, then the "real" copy c-tor will
have this signature:

Foo said:
If so, does that mean I can do this (inside the class
definition):

int bar(Foo x);

You absolutely can do this. This statement declares a function
'bar' that takes one argument of the same type as the instantiated
template and returns an int.
Can I declare the copy constructor differently? In
particular, are any of the following, written inside the
class definition, equivalent to the above:

Foo(const Foo<T> & another);
Foo<T>(const Foo & another);
Foo<T>(const Foo<T> & another);


IIRC, inside the definition of {template<typename T> class Foo}
the type-id "Foo said:
Now say I want to implement my copy constructor outside the
body of the class definition. How do I write the definition
of the function?

template<class T> Foo<T>::Foo(const Foo& other)
{
... // whatever
}
Thanks for any help. I know that a reasonable answer to
some of my questions above is "Try it out, you ninny!"
However, I want to write standard-conforming code, and I am
worried that my compiler and The Standard might not agree
on some points.

There can be two points of view on this. While you are supposed
to write standard code, you are still using a very particular
compiler and your code should also conform to that compiler's
idiosyncrasies.

V
 
M

Matt Bitten

Thanks for the help.

Now, what is it that is NOT a copy constructor, that has everyone so
confused? I read in the standard in 12.8 that a "template
constructor" is not a copy constructor. However, a global search of
the standard turns up no other use of the term "template
constructor". So what is a template constructor?

FWIW, I tried a few things out. I'm using VC++ 7.0. The following
works:

#include <iostream>

template <typename T>
class Foo {
public:
Foo();
Foo(const Foo & another);
Foo & operator=(const Foo & another);
~Foo();
};

template <typename T>
Foo<T>::Foo()
{ std::cout << "default constructor" << std::endl; }

template <typename T>
Foo<T>::Foo(const Foo & another)
{ std::cout << "copy constructor" << std::endl; }

template <typename T>
Foo<T> & Foo<T>::eek:perator=(const Foo & another)
{ std::cout << "copy assignment" << std::endl; return *this; }

template <typename T>
Foo<T>::~Foo()
{ std::cout << "destructor" << std::endl; }

int main()
{
Foo<int> f1; // Try default constructor
Foo<int> f2(f1); // Try copy constructor
f2 = f1; // Try copy assignment
// Implicitly try destructor (twice)
}

And the printout shows that I am successfully overriding all four of
the automatically generated functions.

I can change ALL of the copies of "Foo" with no "<" after them into
"Foo<T>", except for the one after "class", and it still works.

I cannot change any of the "Foo<T>" above into just "Foo". So Foo as
a namespace or a return type, outside the class definition, must be
"Foo<T>". Foo as a parameter type for a member function or the name
of a constructor or destructor, is fine, as is any use of Foo inside
the class definition.

It is not clear to me that this is what the standard says, however.
 
V

Victor Bazarov

Matt Bitten said:
Now, what is it that is NOT a copy constructor, that has everyone so

Everyone? I'd probably refrained from speaking for *everyone*...
confused? I read in the standard in 12.8 that a "template
constructor" is not a copy constructor. However, a global search of
the standard turns up no other use of the term "template
constructor". So what is a template constructor?
[...]
It is not clear to me that this is what the standard says, however.

class Foo {
public:
template<class T> Foo(T const& t); // a template constructor
};

template<class T> class Bar {
public:
template<class U> Bar(const Bar<U>&); // a template constructor
};

The point is that in neither case the template constructor implements
or works in lieu of the compiler-generated copy constructor, although
you might think that if in the first case "T" is Foo, then the c-tor
becomes
Foo(Foo const& t);

and in the second case if U is the same as T, then it becomes

Bar<T>(const Bar<T>&);

The Standard says that it's not going to happen. In both classes Foo
and Bar<T>, the copy constructor that has a very specific signature
is going to be provided and will take over for all copy-construction
needs.

Victor
 

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

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top