Trying to understand why having a parameter pack templated constructor for a class apparently causes both the copy constructor and the copy assignment operator to be optimized out. (Actually I can see how the compiler wouldn't be able to discern the copy constructor signature as different from the templated constructor, but seems like it should be obvious when the copy assignment operator is used)
Example code"
#include <array>
#include <iostream>
struct A
{
std::array<int,3> a;
template<typename ... Args>
A(Args&& ... args)
: a{args ...}
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
A(const A& other)
: a{other.a}
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
A& operator=(const A& other)
{
a = other.a;
std::cout << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
};
int main()
{
A a(1,2.f,3.);
A b = a; // fails (see compiler output)
//A c(a); // also fails (templated constructor is better match)
}
Compile output:
templated_constructror.cpp: In instantiation of ‘A::A(Args&& ...) [with Args = {A&}]’:
templated_constructror.cpp:35:8: required from here
templated_constructror.cpp:11:15: error: cannot convert ‘A’ to ‘int’ in initialization
11 | : a{args ...}
Since you're doing a declaration and assignment in the same expression,
uses a constructor.
Since
ais non-const qualified, the constructor taking an lvalue reference to non-const (A&) is a better match given the argument passed to the constructor.If you actually pass a lvalue reference to a const
A, the code compiles:If you want this to work as expected, add a constructor overload with a parameter of type
A&:Alternatively you could change the set of constructors as follows and the constructor template being a match, if a single constructor argument is provided. (The 2nd and 3rd signature could be implemented in one go using a constructor with a default argument.)