6

I asked this question about overloading the copy constructor and assignment operator with template versions and considering the confusion involving around the question (since it seems to be a compiler bug), I thought I'd try with only template copy constructor and template assignment operator to see what happens. But they are completely ignored by the compiler.

struct BaseClass
{
public:
  BaseClass() {}

  template<typename T>
  BaseClass(const T& a_other)
  {
    int i = 0; // for break point which is not hit
  }

  template<typename T>
  BaseClass& operator= (const T& a_other)
  {
    int i = 0; // for break point which is not hit
    return *this;
  }

};

struct MyClass : public BaseClass
{
};

int main()
{
  MyClass i, j;
  i = j;

  return 0;
}

Why can't I over-ride the defaults with template versions (I suspect the answer will be the defaults are a better match but I would like the template versions to act as defaults as well)? And is there anything I can do to make sure the template versions are called instead of the defaults?

Community
  • 1
  • 1
Samaursa
  • 16,527
  • 21
  • 89
  • 160
  • 1
    Simple answer: the standards mandates so. – David Rodríguez - dribeas Feb 28 '12 at 18:47
  • @DavidRodríguez-dribeas - I'm not disagreeing, but can you cite which section mandates that behavior? – Robᵩ Feb 28 '12 at 18:49
  • 1
    You can't, because the standard says so. A copy constructor is never a template instance, period. You must provide a non-template version, or the compiler-generated one will be used. – n. m. could be an AI Feb 28 '12 at 18:50
  • Please disregard my previous comment, it's wrong. The right statement is "a template does not suppress a compiler-generated copy constructor". A custom copy-constructor, however, does suppress a compiler-generated one. If you manage to create a cooy ctor that provides a worse match than a template, a template will be used. – n. m. could be an AI Feb 28 '12 at 18:59
  • "If you manage to create a cooy ctor that provides a worse match than a template, a template will be used." I am assuming that is impossible...? – Samaursa Feb 28 '12 at 19:00
  • @Samaursa no, it's possible: http://ideone.com/QwjeI – bames53 Feb 28 '12 at 19:19
  • @Samaursa Try having your copy ctor accept const *volatile* reference. – n. m. could be an AI Feb 29 '12 at 17:49

2 Answers2

8
template<typename T>
BaseClass(const T& a_other) 

First of all, this is not a copy-constructor. It is rather a templated constructor.

The copy-constructor should be this:

BaseClass(const BaseClass & a_other)

Notice the difference?

Note that the templated constructor doesn't define copy-constructor. The compiler will still generate a default copy-constructor for you, instead of instantiating the templated constructor.

Same argument for copy-assignment.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    Ah yes, I see it. It is a template constructor but not a copy constructor. (+1) – Samaursa Feb 28 '12 at 18:53
  • A constructor of the form `Baseclass(Baseclass &)` is also a copy constructor, by the way. – Kerrek SB Feb 28 '12 at 20:24
  • @KerrekSB: Actually, there are other forms also : `A(A volatile &)`, `A(A const volatile &)`, `A(A const &, T t = value)`, `A(A const &, T1 t1 = value1, T2 t2 = value2)`, and so on. – Nawaz Feb 28 '12 at 20:30
  • Thankfully, `volatile` is only needed for tape drives, and copying tapes should be passed through the RIAA idiom. Further, defaulted arguments are indeed a neat trick. – Kerrek SB Feb 28 '12 at 20:32
  • @Nawaz: If I create any of those constructors, is the compiler going to create a default constructor anyway? – Samaursa Feb 29 '12 at 17:28
5

As mentioned in answers to your other question, the standard specifically disallows it.

I'd guess that a rationale is that if a non-default for these constructors is necessary it would be because they need to deal with the specifics of the class in question. A 'generic' solution wouldn't make sense and might quietly hide potential problems.

Some people might believe it's bad enough that there's already the 'generic' implicit versions of these functions, which silently does the wrong thing for many classes.

The standardese disallowing template versino of these is here:

From C++03 12.8 "Copying class objects"

  • (Para 1): 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)
  • (Para 9): A user-declared copy assignment operator X::operator= is a non-static non-template member function of class X with exactly one parameter of type X, X&, const X&, volatile X& or const volatile X&
Michael Burr
  • 333,147
  • 50
  • 533
  • 760