Please help with this sample code:
struct A
{
std::string value;
A() {}
A(A const &) {}
template <typename... Args>
A(Args&&... args) : value (std::forward<Args>(args)...) {}
};
int main(void)
{
auto a = A();
auto b = a;
return 0;
}
An error is thrown while compiling:
error: no matching function for call to ‘std::__cxx11::basic_string<char>::basic_string(A&)’
For some reason the compiler wants to call the templated constructor even though the class has a copy constructor. So the question is - why the compiler does not see copy constructor?
In your example, the template constructor is a better match than the non-template constructor because of the universal reference the template constructor uses, which allows the compiler to pass the lvalue a to the constructor as-is, whilst the non-template one requires it to be a const lvalue.
If instead of declaring a like this:
auto a = A();
You declared it like this
const auto a = A();
Then the copy constructor would be chosen instead, since it would be a better match.
To make your example work, you will need to use SFINAE or concepts (if using at least C++20).
With SFINAE:
struct A
{
std::string value;
A() {}
A(A const &) {}
template <typename Arg, typename... Args,
std::enable_if_t<!std::is_same_v<A, std::remove_reference_t<Arg>>>* = nullptr>
A(Arg &&arg, Args&&... args): value (std::forward<Arg>(arg), std::forward<Args>(args)...) {}
};
With concepts:
struct A
{
std::string value;
A() {}
A(A const &) {}
template <typename Arg, typename... Args>
requires (!std::same_as<A, std::remove_reference_t<Arg>>)
A(Arg &&arg, Args&&... args): value (std::forward<Arg>(arg), std::forward<Args>(args)...) {}
};
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