0

I am doing a course C++ Fundamentals for Professionals on educative.io website, it mentioned the above statement added in the question,

I created a small c++ program to experiment the same -

#include<iostream>
using namespace std;

template<typename T1>
class MyTemplateClass
{
    
public:
    T1 data;

    MyTemplateClass()
    {
        cout << "in default const" << endl;
    }

    MyTemplateClass(const MyTemplateClass& other)
    {
        cout << "in default copy const - created automatically" << endl;
        this->data = other.data;
    }
    
    template<typename T>
    MyTemplateClass(const MyTemplateClass<T>& other)
    {
        cout << "in templated copy const" << endl;
        this->data = other.data;
    }
};


int main()
{
    cout << "hello world" << endl;
    MyTemplateClass<int> obj;
    MyTemplateClass<double> obj2(obj);
    MyTemplateClass<int> obj3(obj);

}

For obj3 it calls the default copy constructor which makes sense but for obj2 it calls the templated copy constructor, so I see a use for the constructor that if I have a class that takes T1 = double, we can created an object for it from an object of a class that takes T1 = int.

Does obj2 using template MyTemplateClass(const MyTemplateClass& other) - this function doesn't seem like a valid copy constructor according to the rules of a copy constructor defined in c++ but why is it such a case - since this seems like a valid use case?

user123456
  • 13
  • 5
  • 1
    Unless `T` is exactly `T1` then `MyTemplateClass(const MyTemplateClass& other)` is a [converting constructor](https://en.cppreference.com/w/cpp/language/converting_constructor), not a copy constructor. – François Andrieux Dec 28 '21 at 18:32
  • So, basically, it is nothing but a member function? I am not sure why they even call it a templated constructor in text books and other SO questions, so what they refer to is nothing but MyTemplateClass(const MyTemplateClass& other) when they say templated copy constructor (and it will not be preferred over default copy ctor also) ? – user123456 Dec 28 '21 at 18:38
  • 2
    It's still a constructor, like `MyTemplateClass(int i)` would be. And it is templated. So it is accurate to call is a templated constructor. – François Andrieux Dec 28 '21 at 18:39
  • Oh okay I got it, but that is a valid use-case right? Like I can use to take a templated class object taking int and convert it to an object that takes the template parameter as double right? Like that will be a valid use case? – user123456 Dec 28 '21 at 18:41
  • It makes sense if the you can reasonably define a converting constructor. In this case, `int` and `double` are implicitly interconvertible so the simple conversion constructor works. But it won't work if you use a types that are not interconvertible. For example if you had `MyTemplateClass obj;` instead, then `obj2` and `obj3`'s construction would fail as those constructors cause errors when trying to convert `std::string` to `double` or `int`. – François Andrieux Dec 28 '21 at 18:44
  • @FrançoisAndrieux unless you specialize/SFINAE the template to take different actions based on the types used, for instance to call `std::to_string()` or `std::stoi()`, etc – Remy Lebeau Dec 28 '21 at 18:45
  • @FrançoisAndrieux Got it, this makes sense to me, thank you! Also, thanks for the quick help, appreciate you taking the time out! – user123456 Dec 28 '21 at 18:45
  • @Remy Lebeau Yeah, I was adding a check like std::integral and then initializing the data to an int, but would need quite some checks for the different data types but can be done I think similar to checking for an int – user123456 Dec 28 '21 at 18:48

1 Answers1

1

A constructor template doesn't count as copy constructor even if it has the correct signature of a copy constructor for some template argument.

This is important because if there is no copy constructor declared by the user, then the compiler will declare an implicit one.

So for example

struct A {
    A() {}

    template<typename T>
    A(const T&) { std::cout << "Template called!"; }
};

int main() {
    A a;
    A b = a;
}

will not output Template called!. Instead of the template specialization the implicitly declared copy constructor (which does nothing in this case) is called.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • This surprised me. Oddly this is not the case if the argument is an rvalue reference, yielding a so called universal reference. Is the copy constructor still implicitly generated, but the user provided constructor is preferred? https://godbolt.org/z/xv3vax7o7 – François Andrieux Dec 28 '21 at 18:56
  • 1
    @FrançoisAndrieux The implicitly generated copy constructor is still there, but it is a worse fit in overload resolution because it takes `const A&`, but the forwarding template accepts a `A&` (not `const`-qualified). https://godbolt.org/z/P5jssvjW5 – user17732522 Dec 28 '21 at 19:01
  • If you change `A a;` to `const A a;` the output disappears, so that checks out. Thanks! – François Andrieux Dec 28 '21 at 19:05