c++ why is constructor in this example called twice? - c++

I just try to understand the behaviour of the following situation:
template <typename T1>
struct A{
template <typename T2>
A(T2 val){
cout<<"sizeof(T1): "<<sizeof(T1)<<" sizeof(T2): "<<sizeof(T2)<<endl;
}
T1 dummyField;
};
so - the class is templated with T1 and the constructor is templated with T2
now - if i write:
A<bool> a = A<bool>(true);
the output is as expected:
sizeof(T1): 1 sizeof(T2): 1
however - if i write:
A<bool> a = A<float>(3.5f);
the output is:
sizeof(T1): 4 sizeof(T2): 4
sizeof(T1): 1 sizeof(T2): 4
why is the constructor called twice with template parameter float?
thanks for satisfying my curiosity

How to avoid copying?
In both cases two constructors are called, however you do not see it in the first case as one of them is the compiler generated one. If you want to avoid copying, you need to use a different syntax, like this:
A<bool> a(true);
A<bool> a(3.5f);
Why (and what) copy constructor is called?
A<bool> a = A<bool>(true);
Here the A (bool val) constructor is used to construct the temporary value, while default compiler generated copy constructor is used to perform the copy of A to A. You are copying the same type, and for same type copy constructor is used. The interesting and not obvious fact here is: Template constructor is never used as a copy constructor, even if it looks like one.
A<bool> a = A<float>(3.5f);
Here A<float>(float val) constructor is used first to construct the temporary value, and then A<bool>( A<float> val) templated constructor is used to perform the copy.

in your first example you make a implicit call to the copy constructor
A<bool>(A<bool> const&)
in your second example this wont work as you have two different types
so the compiler has to use your templated constructor to create a new object
declaring
template <typename T2>
A(A<T2>const& val){
cout<<sizeof(val.dummmyField)<<endl;
}
should make this clear

Because you first create a float-instance of the template class.
This is the A<float>(3.5f)-Part.
Then create the A<bool> by covert the A<float> to a A<bool>. So the constructor is first called for the A<float>-instance. The the copy-constructor of A<bool> is called.

Related

Multiple Default Constructors

From this stack overflow question the answer contains this quote:
... definition says that all default constructors (in case there are multiple) ...
How can there be multiple default constructors, and why may that be useful or allowed by the standard?
Default constructors don't have to have no parameters; they just need to be invocable with no arguments.
This condition is fulfilled by any constructor whose arguments all have defaults.
[class.dtor/1]: A default constructor for a class X is a constructor of class X for which each parameter that is not a function parameter pack has a default argument (including the case of a constructor with no parameters). [..]
struct Foo
{
Foo(int a = 0);
Foo(std::string str = "");
};
Now, of course, in this example you cannot actually instantiate a Foo using either of them without providing an argument (the call would be ambiguous). But Foo is still usable, and these are still "default constructors". That's just how the standard has decided to categorise things, for the purpose of defining rules. It doesn't really affect your code or programming.
(By the way, I didn't want to distract but you should have explicit on both of those!)
Here's an example of a class with two default constructors that can be default constructed:
struct Foo
{
Foo(); // #1
template <class... Args>
Foo(Args...); // #2
};
auto test()
{
Foo f{}; // ok calls #1
}

Initialising template variables using initializer list

I looked at a piece of code and I am trying to understand how it works and so here is a minimal working example
template <typename T>
class A
{
public:
A() : _mem(T()) {};
private:
T _mem;
};
The first thing I was not exactly clear about is the initialisation of _mem in the initialiser list. What is this technique(?) called? If I look in the debugger _mem is set to 0. If there is a c++11 way to do the same thing could I receive some comments on that?
This is just to safeguard against an uninitialized A::_mem when T is a POD type or a built-in type (like an int). Using a constructor initializer list of : _mem(T()) will default construct a T and initialize _mem with it. For example:
struct POD {
int num;
};
// ...
A<POD> a;
Here, a._mem would be unitialized (in this case, this means a._mem.num is unitialized.) The : _mem(T()) prevents that from happening and will initialize a._mem.num to 0.
However, since C++11 you can just use inline initialization instead:
template <typename T>
class A {
public:
A() {};
private:
T _mem{};
};
T _mem{}; will default-construct _mem, which in turn means POD::num will be default-constructed, which for an int means it will be zero-initialized.
If this has a name, I don't know it.
What's happening:
T() constructs a temporary T and Zero Initializes it.
_mem(T()) makes _mem a copy of the temporary T. Note: A modern compiler will almost certainly elide the copy and simply zero initialize _mem. This still requires that T be copy-or-moveable, so _mem(T()) and _mem() are not exactly the same.
The only relevant C++ 11 difference I can think of is you can use curly braces, _mem{T{}}, for List Initialization. Not useful here, but very useful in other circumstances.

How do I call make_shared or make_unique with a templated Constructor

How can I call make_shared or make_unique on a class that has a templated constructor? Here's an example:
class A
{
/// constructor shared ptr
A(shared_ptr<X> x) ...
/// constructor that creates new shared ptr
template <class T> A() : A(make_shared<T>(...)) {}
};
make_shared<A<T>>() doesn't make sense (nor does it compile), since that would rather be for a templated class, not a templated constructor.
Neither make_shared<A><T>() nor make_shared<A>(<T>()) compile---nor look like they should. Ditto on make_shared<A, T>()
Is there any way to specify the template for the constructor call in the call to make_shared? I assume the answer would apply for make_unique; if it doesn't, please indicate that. Thanks!
(To clarify how the templating is working, I've edited the code.)
There is no way to use a class constructor template at all without template argument deduction. So any template parameters must be deduced from arguments provided, never specified explicitly at call time.
This isn't restricted to any of the make_* functions; this is no way of initializing the object at all. That constructor cannot be called. Your compiler isn't required to complain about this constructor, but there's simply no way to call it.

C++ template copy constructor on template class

I have a template class that has a template copy constructor. The problem is when I instantiate this class using another instance of this class with the same template type, my template copy constructor is not called. Why doesn't it match?
Here is the code snippet:
#include <iostream>
template <typename T>
class MyTemplateClass
{
public:
MyTemplateClass()
{
std::cout << "default constructor" << std::endl;
}
/*
MyTemplateClass(const MyTemplateClass<T>& other)
{
std::cout << "copy constructor" << std::endl;
}
*/
template <typename U>
MyTemplateClass(const MyTemplateClass<U>& other)
{
std::cout << "template copy constructor" << std::endl;
}
};
int main()
{
MyTemplateClass<int> instance;
MyTemplateClass<int> instance2(instance);
return EXIT_SUCCESS;
}
The output is
default constructor
But if I explicitly write the default copy constructor (by uncommenting it), then the output becomes
default constructor
copy constructor
I really don't get it. I tested it with my local compiler (Clang 500.2.79) and with this one (GCC 4.9.2) and got the same result.
A copy constructor is of the form X(X& ) or (X const&) and will be provided for you by the compiler if you didn't declare one yourself (or a few other conditions which are not relevant here). You didn't, so implicitly we have the following set of candidates:
MyTemplateClass(const MyTemplateClass&);
template <typename U> MyTemplateClass(const MyTemplateClass<U>&);
Both are viable for
MyTemplateClass<int> instance2(instance);
Both take the same exact arguments. The issue isn't that your copy constructor template doesn't match. The issue is that the implicit copy constructor is not a function template, and non-templates are preferred to template specializations when it comes to overload resolution. From [over.match.best], omitting the unrelated bullet points:
Given these definitions, a viable function F1 is defined to be a better function than another viable function
F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
— [...]
— F1 is not a function template specialization and F2 is a function template specialization, or, if not that,
— [...]
That's why it calls your implicit (and then, your explicit) copy constructor over your constructor template.
When you do not have a copy constructor in you code, the compiler will implicitly generate it. Therefore when this line is executed:
MyTemplateClass<int> instance2(instance);
A copy constructor is being executed, though obviously not yours. I think that templating has nothing to do with it.
Read more about it here: Implicitly-defined copy constructor
I think REACHUS is right. The compiler is generating a default copy-constructor (as it would with a non-template class too) and preferring this over your template as it's more specialised.
You should make your "normal" copy-constructor private, or better, use the C++11 'deleted' keyword to mark the function as unusable.
However, this doesn't compile. Sorry, I wasn't able to test it at the time.

Multiple copy constructors specified

With Visual C++ 2010, I have a class like this:
class MyClass{
public:
MyClass(){}
MyClass(MyClass &){/*...*/} //A
MyClass(const MyClass &){/*...*/} //B
template<typename T> MyClass(T &&t){ static_assert(
!std::is_same<typename
std::remove_cv<typename std::remove_reference<T>::type>::type,
MyClass>::value,
"Wrapping over wrapping is not allowed!"); } //C
};
int main(int, char**){
MyClass a;
const MyClass b(a); //assert fail if line A removed
auto c=b; //assert fail if line B removed
}
//If both A and B exists
//Warning C4521: multiple copy constructors specified
//Furthermore, if both A and B removed
//No error or warnings; VC2010 accepts peacefully.
//In debug mode you will find the compiler generated trivial copy constructor
According to C++ standard, both line A and B are considered copy constructors, and C is a convert constructor. It is not surprising that I receive a warning that I declared multiple copy constructors. However, if I remove any of them, the static_assert fails and the code would not compile, that means the template constructor received control.
I am sure that this behaviour follows the rule of function overloading. However is this a conflict of two rules? If A and B are copy constructors and one of them was declared, any attempt to copy the objects should not drop to the template, is it right?
Update:
According to N3242, 12.8.7,
"a member function template is NEVER INSTANTIATED to perform the copy of a class object to an object of its class type."
the correct implementation should be:
No assert failure should occur when either A or B or both removed.
If line B is removed, construction of c should fail because b is const.
If both lines are removed, compiler should generate a copy constructor for the class.
It is up to the implementation to warn the user if both lines exists.
Any comment?
First of all, template<T> should be template <typename T>.
I am using gcc 4.4.3 on 64-bit Ubuntu Linux, the codes behave differently from what you have demonstrated in the post.
If nothing changed, the codes could be compiled without any warning. The constructor A and B are evoked one after another.
If I comment line A, it fails to be compiled just as what you said: failing in line const MyClass b(a);. The reason is that the object a is not constant, so constructor B can not be matched and the compiler has to instantiate the template constructor. Of course, const MyClass and MyClass are different types.
However, if I comment line B only, the codes could be compiled successfully and the template copy constructor was evoked. Object b is a constant object, so construct A can not be matched and the compiler instantiate the template constructor. However, the question remains: should the static_assert fails or not? The difference may be because of the platform/compiler difference. GCC seems implementing the is_same<MyClass&&, MyClass>::value to be true. You may use typeid to print out both of the types.
If A and B are copy constructors and one of them was declared, any attempt to copy the objects should not drop to the template, is it right?
A constructor that is not a copy constructor can still be used to copy objects. In your case the constructor instantiated from the constructor template is used for copying the object. Which is fine.