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 ...}
A possible fix:
#include <array>
#include <iostream>
#include <type_traits>
struct A {
std::array<int, 3> a;
template <typename... Args,
std::enable_if_t<sizeof...(Args) != 1, bool> = true>
A(Args&&... args) : a{args...} {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
template <typename Arg,
std::enable_if_t<!std::is_same<std::decay_t<Arg>, A>::value,
bool> = true>
A(Arg&& arg) : a{arg} {
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; // now OK
A c(a); // now OK
}
It can certainly be improved and I'm not sure it is what you want to achieve. Basically first constructor catches only initialisation with 0 or 2+ arguments. The second one is used with only one argument if it's not a A. The third one is the normal copy constructor. live Demo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With