0

Take the following,

template<class T>
struct Foo {
    Foo(){}

    // a template constructor "generalized" over related types
    template<class U>
    Foo(Foo<U> const&) {
        std::cout << 1;
    }

    // copy constructor
    Foo(Foo const&) {
        std::cout << 2;
    }
};

and its user:

void main() {
   Foo<int> f1;
   Foo<const int> f2(f1); // prints 1
   Foo<const int> f3(f2); // prints 2
}

Even without the explicit copy constructor, compiler generates one and uses that for f3(f2).

Is there a way to force the template overload? For example, can the copy-constructor be SFINAE'd out? This is in order to avoid code duplication, as, interestingly enough, there doesn't seem to be a way to use delegating constructors either (delegating from the copy constructor to the template one).

sly
  • 1,722
  • 1
  • 10
  • 15
  • nope, that isn't the same, and it renders `f3(f2)` an error since the overload resolution still picks the copy constructor and errors out as `delete`d. (comment i replied was asking if `delete` is an option) – sly Jul 28 '16 at 23:27

1 Answers1

5

A constructor template can never be a copy constructor, so if you don't define one, the compiler will implicitly do it for you, as you've found out.

One workaround to avoid code duplication is to define a third constructor and delegate to it from both your constructors shown above.

template<class T>
struct Foo {
    Foo(){}

    struct tag{};

    // a template constructor "generalized" over related types
    template<class U>
    Foo(Foo<U> const& f)
    : Foo(tag{}, f)
    {
        std::cout << 1 << '\n';
    }

    // copy constructor
    Foo(Foo const& f) 
    : Foo(tag{}, f)
    {
        std::cout << 2 << '\n';
    }

private:
    template<class U>
    Foo(tag, Foo<U> const&)
    {
        std::cout << 3 << '\n';
    }
};

Live demo

Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • interesting suggestion. actually solves the practical use case well. however, is not a straight answer to the question "can the copy constructor be disabled" (was looking for a non-implicit version with a default sfinaed argument etc. -- perhaps the answer is no). Being moot at this point i guess.... – sly Jul 28 '16 at 23:34
  • 2
    @sly I don't see how you can SFINAE-disable the copy constructor. It's not a template, so there's no deduction involved, which is necessary for SFINAE to kick in. – Praetorian Jul 28 '16 at 23:38