Why can't a copy constructor be templated? [duplicate] - c++

This question already has answers here:
Copy constructor of template class
(2 answers)
What is a converting constructor in C++ ? What is it for?
(3 answers)
Closed 1 year ago.
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?

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.

Related

what function were called when initiate a string with both char array and = operator [duplicate]

This question already has answers here:
Why copy constructor is not called in this case?
(4 answers)
Closed 3 years ago.
According to the explanation in C++ primer 5th.
Initiate a string with char array and using =
operator. It will actually do below two things:
1: Call constructor which accept a const char * to create a temporary string object.
2: Call copy constructor to initiate the true variable;
chapter 13.1 page 618
string null_book = "9-999-99999-9"; // copy initialization
I made a test. and it seems that when I initiate A object with a cahr array.
copy construtor have never been called.
#include <iostream>
int b =5;
using namespace std;
class A
{
public:
A(const char * ch) :chr(*ch) {cout << "contruct ";};
A(const A & a) : chr(0) {cout << "copy_construc ";::b = 2;} ;
A &operator=(const A & a) {cout << "assignment"; return *this;};
char chr;
};
int main() {
A a = "qweqeasd";
cout << b;
cout << a.chr;
A c = A("wrwsx");
cout << b;
cout << c.chr;
}
output:
contruct 5qcontruct 5w
What you have here is called copy-initialization.
A a = "qweqeasd";
If T is a class type and the cv-unqualified version of the type of other is T or a class derived from T, the non-explicit constructors of T are examined and the best match is selected by overload resolution. The constructor is then called to initialize the object.
Here the best match is the constructor A(const char * ch) and that is why the output starts with contruct .

C++ uses the default copy constructor even though the user defines one with a template? [duplicate]

This question already has answers here:
C++ template copy constructor on template class
(3 answers)
Closed 4 years ago.
After a whole day of bug tracing in C++ yesterday I reduced my problem to this:
#include <iostream>
class A {
public:
virtual void id() { std::cerr << "This is A\n"; }
};
class A1 : public A {
public:
virtual void id() { std::cerr << "This is A1\n"; }
};
class A2 : public A {
public:
virtual void id() { std::cerr << "This is A2\n"; }
};
template <class T> class jp {
public:
T* ptr;
jp<T> () { ptr = 0; }
jp<T> ( T a ) {
std::cerr << "Recording address\n";
ptr = &a;
}
template <class S> jp<T> ( const jp<S>& s ) {
s.ptr->id();
ptr = s.ptr;
}
/* surely the above template defines "jp<T> ( const jp<T>& s )"
* but the behaviour is different when it is duplicated as follows *
jp<T> ( const jp<T>& s ) {
s.ptr->id();
ptr = s.ptr;
}
*/
};
int main() {
A a;
A1 a1;
jp<A> jpa1(a); // make a jp<A>
jp<A> jpa2(jpa1); // copy constructor
jp<A1> jpa3(a1); // make a jp<A1>
jp<A> jpa4(jpa3); // copy constructor
jp<A1> jpa5(jpa3); // copy constructor
}
I have defined a copy constructor haven't I? It is
template <class S> jp<T> ( const jp<S>& s )
in the special case when T equals S. Assuming this there should be 5 lines of output, but I only get three:
Recording address
Recording address
This is A1
Uncommenting the section which repeats the already defined constructor (but without a template) gives the five lines of output I was expecting
Recording address
This is A
Recording address
This is A1
This is A1
Please could someone explain? I have read Stroustrup several times and never expected this! what else similar should I know about that I wasn't told?;)
The class A2 is there only to indicate that A might have many subclasses and it is not a trivial matter to duplicate code for each of them.
Thanks!
I have defined a copy constructor haven't I?
No, you have not. A copy constructor is never a template. What you have defined is a constructor that allows you to construct a jp<T> from any jp<S> (i.e. (jp<int> from a jp<double>)
Since you have not actually defined a copy constructor the compiler makes one for you and since that wins in overload resolution you never see
template <class S> jp<T> ( const jp<S>& s )
get called.

Why compilers generate a copy/move constructors when there is a templated constructor?

Mechanism for this is well explained here: Template "copy constructor" does not prevent compiler-generated move constructor, but I would like to better undestand why it is made this way. I understand that move constructor is not generated even if any other constructor is written by the programmer, because it is an indication that construction of object is non trivial and auto generated constructor will probably be wrong. Then why templated constructors that have the same signature as copy constructors are not simply named copy constructors?
Example:
class Person {
public:
template<typename T>
Person(T&& t) : s(std::forward<T>(t)) {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
Person(int n) {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
// No need to declare copy/move constructors as compiler will do this implicitly
// Templated constructor does not inhibit it.
//Person(const Person&) = default;
//Person(Person&&) = default;
private:
std::string s;
};
and then:
Person p("asd"); // OK!
//Person p4(p); // error as Person(T&&) is a better match
if I make p const:
const Person p("asd");
Person p4(p); // thats ok, generator constructor is a better match
but if I explicitly delete even a move constructor with:
Person(Person&&) = delete;
then auto generation of constructors is inhibited.
You understand wrong.
struct noisy {
noisy() { std::cout << "ctor()\n"; }
noisy(noisy&&) { std::cout << "ctor(&&)\n"; }
noisy(noisy const&) { std::cout << "ctor(const&)\n"; }
noisy& operator=(noisy&&) { std::cout << "asgn(&&)\n"; return *this; }
noisy& operator=(noisy const&) { std::cout << "asgn(const&)\n"; return *this; }
};
struct test {
noisy n;
test(int x) { (void)x; }
};
test has generated move/copy construct/assignment.
Live example.
A copy/move construct/assignment written by a programmer results in the other ones being suppressed.
Now, writing a constructor suppresses the zero-argument constructor. That may be why you are confused.
Templated constructors with the same signature as copy constructors are not copy constructors because the standard says so.
As it happens, templated code is rarely the correct code for a copy or move constructor/assignment.
The fact that forwarding references often grab self& and self const&& copy/move over the actual copy/move operations is a problem. C++ isn't perfect.
Usually the way to avoid this is:
template<class T,
class=std::enable_if_t<
!std::is_same<std::decay_t<T>, Person>::value
>
>
Person(T&& t) : s(std::forward<T>(t)) {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
or !std::is_base_of<Person, std::decay_t<T>>::value which covers some other situations (like inheriting constructors).

Copy constructor of template class

I read that template copy-con is never default copy onstructor, and template assignment-op is never a copy assignment operator.
I couldn't understand why this restriction is needed and straight away went online to ideone and return a test program but here copy constructor never gets called on further googling I came across templatized constructor and tried that but still it never calls copy constructor.
#include <iostream>
using namespace std;
template <typename T> class tt
{
public :
tt()
{
std::cout << std::endl << " CONSTRUCTOR" << std::endl;
}
template <typename U> const tt<T>& operator=(const tt<U>& that){std::cout << std::endl << " OPERATOR" << std::endl;}
template <typename U> tt(const tt<U>& that)
{
std::cout << std::endl << " COPY CONSTRUCTOR" << std::endl;
}
};
tt<int> test(void)
{
std::cout << std::endl << " INSIDE " << std::endl; tt<int> a; return a;
}
int main() {
// your code goes here
tt<int> a ; a = test();
return 0;
}
Can someone explain me the whole reason behind putting this restriction and also how to write a copy constructor of template class.
Thanks
I can't comment on why this is how it is, but here's how you write a copy constructor and assignment operator for a class template:
template <class T>
class A
{
public:
A(const A &){}
A & operator=(const A& a){return *this;}
};
and that's it.
The trick here is that even though A is a template, when you refer to it inside the class as A (such as in the function signatures) it is treated as the full type A<T>.
There are strict rules what constitutes a copy constructor (cf. C++11, 12.8):
It is not a template.
For a class T, its first argument must have type T & or T const & or T volatile & or T const volatile &.
If it has more than one argument, the further arguments must have default values.
If you do not declare a copy constructor, a copy constructor of the form T::T(T const &) is implicitly declared for you. (It may or may not actually be defined, and if it is defined it may be defined as deleted.)
(The usual overload resolution rules imply that you can have at most four copy constructors, one for each CV-qualification.)
There are analogous rules for move constructors, with && in place of &.

C++ basic constructors/vectors problem (1 constructor, 2 destructors)

Question is probably pretty basic, but can't find out what's wrong (and it leads to huge of memleaks in my app):
class MyClass {
public:
MyClass() { cout << "constructor();\n"; };
MyClass operator= (const MyClass& b){
cout << "operator=;\n"; return MyClass();
};
~MyClass() { cout << "destructor();\n"; };
};
main() {
cout << "1\n";
vector<MyClass> a;
cout << "2\n";
MyClass b;
cout << "3\n";
a.push_back(b);
cout << "4\n";
}
The output is:
1
2
constructor();
3
4
destructor();
destructor();
Why are there 2 destructors?
If it's because a copy is created to be inserted into vector - how come "operator=" is never called?
When the b object gets pushed onto the vector a copy is made, but not by the operator=() you have - the compiler generated copy constructor is used.
When the main() goes out of scope, the b object is destroyed and the copy in the vector is destroyed.
Add an explicit copy constructor to see this:
MyClass( MyClass const& other) {
cout << "copy ctor\n";
};
If you want to log all copies and constructions you should add an explicit copy constructor so that the compiler doesn't create one for you.
MyClass( const MyClass& )
{
cout << "Copy constructor\n";
}
You can, in your copy constructor, call your assignment operator. It is a reasonably common way of implementing things, however with your definition of operator=, this may have serious problems.
You have an unconventional implementation of operator=. operator= should return a reference to the class on which it is called (to enable proper chaining), but you return a new class instance by value. This means that if you tried to call operator= from your copy constructor you may well end up with infinite recursion. Try this operator= instead:
MyClass& operator=( const MyClass& )
{
cout << "operator=\n";
return *this;
}
When defining an assignment operator you should always consider the possibility that the parameter and *this may refer to the same object and ensure that the definition of the operator won't have any unintended effects in this scenario.