Let following program:
#include <variant>
struct A{
A(){}
~A(){}
A(const A&){}
A& operator = (const A&) { return *this;}
A(A&&){}
A& operator = (A&& ) { return *this; }
using var = std::variant<int, float>;
var v;
template<typename T>
A(T&& t): v(std::forward<T>(t)){}
};
struct B
{
A m_a;
B( A a) : m_a(a) //calls template constructor instead of copy!
{}
};
Live example: godbold example
Q: Why template generic constructor chosen instead of copy (or move) constructor?
Edit : I think that, this is not duplicate of Why isn't this templated move constructor being called?
Because that issue asks why templated constructor NOT called?. That issue problem is - NOT called templated constructor.
I'm asking why templated constructor IS calling?.
My problem is -- on the contrary, calling templated constructor.
:)
It's just a better match. The template will instantiate a ctor that looks like:
A(T& t): v(t)){}
either pass as const&
https://godbolt.org/z/78bdzczE5
or create better matching ctor
https://godbolt.org/z/b8WvjW38T
Related
Just failed an interview because of this, and I'm still confused:
class A
{
public:
A(int a) : a_(a) {}
// Copy constructor
// Assignment operator
private:
int a_;
};
class B : public A
{
public:
B(int a, int b) : A(a), b_(b) {
}
// Copy constructor
// Assignment operator
private:
int b_;
};
How do you implement the copy constr/assignment op, and why does the constructor of B have to have an A initialized in the initializer list? It doesn't work if it's not in the list.
How do you implement the copy constr/assignment op
Trick question, I think. In this case the best option is to do absolutely nothing. Neither class contains (and owns) any resources requiring more than the default special member functions. Observe the Rule of Zero.
Some style guides recommend explicitly defaulting special member functions. In this case
class A
{
public:
A(int a) : a_(a) {}
A(const A &) = default;
A& operator=(const A &) = default;
private:
int a_;
};
may be appropriate.
why does the constructor of B have to have an A initialized in the initializer list?
All class members and base classes must be fully constructed before entering the body of a constructor.
B(int a, int b)
{ // Entering constructor's body. A must be constructed before we get here.
}
A has no default constructor, so the constructor it does have must be explicitly called in the initializer list to construct the base class before the construction of B can proceed.
Addressing comment
A's copy constructor and assignment operator are trivial:
A(const A & src): a_(src.a_)
{
}
A& operator=(const A & src)
{
a_ = src.a_;
return *this;
}
B is a bit trickier because it also has to make sure A is copied
B(const B & src): A(src), // copy the base class
b_(src.b_)
{
}
B& operator=(const B & src)
{
A::operator=(src); // assign the base class by explicitly calling its
// assignment operator
b_ = src.b_;
return *this;
}
Note: If I were hiring, I'd take the programmer who called me out on the trick question over the programmer who did the extra work and risked an unforced error.
why does the constructor of B have to have an A initialized in the
initializer list?
A only has one constructor which takes an int. B has A as a base class, which means that every B object must first construct an A object. How else are you going to construct that A object with it's required parameter except by using an initialiser list?
How do you initialize a copy constructor of constructor that has as reference a class. I simply do not know what to put after the colon in order to initialize it.
class Me{
public:
Me (const otherMe& t)
:other_me(t)
{}
//copy constructor
Me(const Me& me)
: /*what do you put here in order to write
the line of code bellow. I tried t(t), and gives me the
warning 'Me::t is initialized with itself [-Winit-self]' */
{cout << t.getSomthing() << endl;}
private:
const otherMe& other_me;
};
Let's say you have two classes, Value, and Wrapper:
class Value { // stuff... };
class Wrapper; // This one contains the reference
We can write the constructor and copy-constructor like so:
class Wrapper {
Value& val;
public:
Wrapper(Value& v) : val(v) {}
Wrapper(Wrapper const& w) : val(w.val) {}
};
This wold also work if Value& were a const reference! In addition, if you can write Wrapper as an aggregate, it'll automatically get a copy constructor:
class Wrapper {
public:
Value& val;
// copy constructor automatically generated
};
This question already has answers here:
Explicit copy constructor
(3 answers)
Closed 3 years ago.
I came across this curio and don't understand why the use of explicit constructors would cause this to fail.
I was trying to generate and initialize objects from configuration data using lambdas. I found that the lambda could only return a copy of the object if the object's class definition did not use explicit constructors. This code sample is a simplistic example of what I found.
class foo {
public:
explicit foo() : _a(0) {}
explicit foo(int val): _a(val) {}
explicit foo(const foo& o) : _a(o._a) {}
explicit foo(foo&& o) : _a(std::move(o._a)) {}
foo& operator()(const foo& rhs) { if (this != &rhs) { _a = rhs._a; } return *this; }
foo& operator()(foo&& rhs) { _a = std::move(rhs._a); return *this; }
int a() const { return _a; }
void a(int val) { _a = val; }
private:
int _a;
};
auto makeFoo = [](int val) -> foo { return foo(val); };
As written the sample code fails to compile with the following errors on the makeFoo line:
In static member function ‘static foo<lambda(int)>::_FUN(int)’:
error: no matching function for call to ‘foo::foo(foo)’
However, if I remove the 'explicit' tags from the foo constructors, the code compiles just fine.
Can someone enlighten me as to why the constructors cannot be explicit in this lambda?
First of all, review the documentation about the explicit keyword.
Specifies that a constructor or conversion function (since C++11) is explicit, that is, it cannot be used for implicit conversions and copy-initialization.
Basically, the explicit copy constructor means that the copy constructor will not be called implicitly.
You don't need to define your copy/move constructor, the compiler will generate them for you. Same for the copy/move assignment. Just remove them and you will be fine.
class foo {
public:
foo() = default;
explicit foo(int val): _a(val) {}
int a() const { return _a; }
void a(int val) { _a = val; }
private:
int _a{0};
};
Starting with C++11, there can be two copy constructors, one taking a parameter of type T&, and one taking a parameter of type const T&.
I have a situation where (seemingly) adding a second copy constructor causes neither one to get called, when the constructors are inherited in a derived class. The copy constructor is overridden by a templatized constructor when both are present.
Here is a MWE:
struct A {
template <typename... Args>
A (Args&&... args)
{ std::cout << "non-default ctor called\n"; }
A (A&) { std::cout << "copy ctor from non-const ref\n"; }
};
struct C :public A { using A::A; };
int main() {
C c1;
C c2(c1);
}
Running this code, we see output
non-default ctor called
copy ctor from non-const ref
which is as expected.
However, adding an additional constructor to struct A as follows:
A (const A&) { }
somehow causes the other copy constructor not to get called, so the output becomes
non-default ctor called
non-default ctor called
In my use case, I want to inherit all the constructors from a base class into a derived class, including the copy constructors and anything else. But it seems that somehow the two copy constructors don't get inherited when they are both present. What is going on here?
From https://en.cppreference.com/w/cpp/language/using_declaration
If one of the inherited constructors of Base happens to have the signature that matches a copy/move constructor of the Derived, it does not prevent implicit generation of Derived copy/move constructor (which then hides the inherited version, similar to using operator=).
So
struct C :public A { using A::A; };
is
struct C :public A
{
using A::A;
C(const C&) = default;
C(C&&) = default;
};
where C(const C&) = default; is similar to
C(const C& c) : A(static_cast<const A&>(c)) {}
So with
struct A {
template <typename... Args>
A (Args&&... args)
{ std::cout << "non-default ctor called\n"; }
A (A&) { std::cout << "copy ctor from non-const ref\n"; }
};
template constructor is chosen, but
struct A {
template <typename... Args>
A (Args&&... args)
{ std::cout << "non-default ctor called\n"; }
A (const A&) { std::cout << "copy ctor from const ref\n"; }
A (A&) { std::cout << "copy ctor from non-const ref\n"; }
};
A (const A&) is chosen.
As you can notice, there is also a defect:
The semantics of inheriting constructors were retroactively changed by a defect report against C++11. Previously, an inheriting constructor declaration caused a set of synthesized constructor declarations to be injected into the derived class, which caused redundant argument copies/moves, had problematic interactions with some forms of SFINAE, and in some cases can be unimplementable on major ABIs. Older compilers may still implement the previous semantics.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0136r1.html
With that defect, your class C would be
struct C :public A
{
using A::A;
template <typename ...Ts>
C(Ts&&... ts) : A(std::forward<Ts>(ts)...) {} // Inherited.
C(const C&) = default;
C(C&&) = default;
};
So you call C(C& c) : A(c) {} (after template substitution).
Trying to resolve error C2248 related to abstract base class using implementation of copy/move ctors/assignment operators and dtor (Rule of Five) and a few questions come up:
1) Why does the rule of 5, primarily relating to the dtor, apply when the unique_ptr data members are handled automatically? The dtor implementation should be left empty correct, since the unique_ptrs are automatically destroyed once their owners go out of scope?
2) Suppose another class had a member of type std::unique_ptr of a vector of the same type. In order for this class to be copyable, it must have a copy ctor and copy assignment operator that clone the unique_ptr data member? I have seen this solution, but is seems like the original poster just switched over to shared_ptr for the sake of removing the error alone with little consideration of ownership management. Is this the correct strategy?
3) Consider the same case as question 2 above relating to vector of unique_ptr. Should dtor include a call to clear() the vector?
4) The assignment operators for the Derived1 are not correct. But the base class is supposed to have copy and move assignment operators, since it has copy/move ctors (rule of 4/5). These can't actually be used outside of the class since it is abstract and thus no instances will be assigned. But how do I utilize this code from the derived classes? Each derived class needs to be able to move/copy the base data members and it's own data members. I'm not sure what to do.
#include <algorithm>
#include <memory>
#include <vector>
#include <iostream>
class Base{
public:
Base() : m_subBases(){};
/* copy ctor */
Base(const Base& other) : m_subBases(){
*this = other;
};
/* move ctor */
Base(Base&& other) : m_subBases(){
*this =std::move( other);
};
/* Move assignment operator*/
Base& operator=(Base&& other){
m_subBases = std::move(other.m_subBases);
return *this;
};
/* Copy assignment operator */
Base& operator=(const Base& other){
for(int i = 0; i < other.m_subBases.size(); i++)
m_subBases.push_back(other.m_subBases[i]->clone());
return *this;
};
/* virtual dtor */
virtual ~Base(){
m_subBases.clear();
};
/* Used for creating clones of unique_ptrs */
virtual std::unique_ptr <Base> clone() const= 0;
/* Do something */
virtual void execute(float f) = 0;
//Omitted data member access methods
protected:
std::vector < std::unique_ptr <Base> > m_subBases;
};
class Derived1 : public Base{
public:
Derived1() : Base(){};
/* copy ctor */
Derived1(const Derived1& other) : Base(other){
*this = other;
};
/* move ctor */
Derived1(Derived1&& other) : Base(std::move(other)){
*this = std::move(other);
};
/* Move assignment operator*/
Derived1& operator=(Derived1&& other){
//This is redundant when called in the move ctor because
// of the call to Base(std::move(other))
m_subBases = std::move(other.m_subBases);
m_string = other.m_string;
return *this;
};
/* Copy assignment operator */
Derived1& operator=( const Derived1& other){
//This is redundant when called in the copy ctor because
// of the call to Base(other)
for(int i = 0; i < other.m_subBases.size(); i++)
m_subBases.push_back(other.m_subBases[i]->clone());
m_string = other.m_string;
return *this;
};
/* virtual dtor */
virtual ~Derived1(){};
/* Used for creating clones of unique_ptrs */
virtual std::unique_ptr <Base> clone() const{
return std::unique_ptr <Base> (new Derived1(*this));
};
virtual void execute(float f){
std::cout << "Derived1 " << f << std::endl;
};
protected:
std::string m_string;
};
I'd like to offer an alternative approach. Not the Scary Rule of Five, but the Pleasant Rule of Zero, as #Tony The Lion has already suggested. A full implementation of my proposal has been coded by several people, and there's a fine version in #R. Martinho Fernandes's library, but I'll present a simplified version.
First, let's recap:
The Rule of Zero: Don't write a copy- or move-constructor, a copy- or move-assignment operator, or a destructor. Instead, compose your class of components which handle a single responsibility and encapsulate the desired behaviour for the individual resource in question.
There's an obvious caveat: When you design the single-responsibility class, you must of course obey:
The Rule of Five: If you write any one of copy- or move-constructor, copy- or move-assignment operator, or destructor, you must implement all five. (But the "five" functions needed by this rule are actually: Destructor, Copy-Const, Move-Const, Assignment and Swap.)
Let's do it. First, your consumer:
struct X;
struct Base
{
std::vector<value_ptr<X>> v;
};
struct Derived : Base
{
};
Note that both Base and Derived obey the Rule of Zero!
All we need to do is implement value_ptr. If the pointee is non-polymorphic, the following will do:
template <typename T>
class value_ptr
{
T * ptr;
public:
// Constructors
constexpr value_ptr() noexcept : ptr(nullptr) { }
constexpr value_ptr(T * p) noexcept : ptr(p) { }
// Rule of Five begins here:
~value_ptr() { ::delete ptr; }
value_ptr(value_ptr const & rhs) : ptr(rhs.ptr ? ::new T(*rhs.ptr) : nullptr) { }
value_ptr(value_ptr && rhs) noexcept : ptr(rhs.ptr) { rhs.ptr = nullptr; }
value_ptr & operator=(value_ptr rhs) { swap(rhs); return *this; }
void swap(value_ptr & rhs) noexcept { std::swap(rhs.ptr, ptr); }
// Pointer stuff
T & operator*() const noexcept { return *ptr; }
T * operator->() const noexcept { return ptr; }
};
template <typename T, typename ...Args>
value_ptr<T> make_value(Args &&... args)
{
return value_ptr<T>(::new T(std::forward<Args>(args)...));
}
If you would like smart pointer that handles polymorphic base class pointers, I suggest you demand that your base class provide a virtual clone() function, and that you implement a clone_ptr<T>, whose copy constructor would be like this:
clone_ptr(clone_ptr const & rhs) : ptr(rhs.ptr ? rhs.ptr->clone() : nullptr) { }