I just wrote following simple code but it doesnt compile:
#include <iostream>
#include <string>
class Obj{
public:
std::string name = "Name";
std::string l_name = "LastName";
template<typename P>
Obj(P&& param): name{std::forward<P>(param)} { }
friend std::ostream& operator<<(std::ostream& os, const Obj& obj);
};
std::ostream& operator<<(std::ostream& os, const Obj& obj) {
os << obj.name << ":" << obj.l_name;
return os;
}
void print() {
std::cout << "}";
}
template<typename T, typename ...Args>
void print(T param, Args... args) {
std::size_t count = sizeof...(args);
std::cout << param;
if ( count != 0 ) {
std::cout << ",";
}
print(args...);
}
template<typename... Args>
void run(Args... args) {
std::cout << "{";
print(args...);
}
int main() {
Obj obj{"obj"};
run("1", "2", 1.3, std::string{"Some Message"}, obj);
return 0;
}
I just used simple parameter pack and perfect forwarding example but gives following error:
main.cpp: In instantiation of ‘Obj::Obj(P&&) [with P = Obj&]’:
main.cpp:49:8: required from here
main.cpp:12:21: error: no matching function for call to ‘std::__cxx11::basic_string::basic_string()’
12 | Obj(P&& param): name{std::forward<P>(param)} {
...
If i dont use the obj paramater in the run function, the example works as expected.
Unfortunately
template<typename P>
Obj(P&& param): name{std::forward<P>(param)} { }
is too greedy, and catch Obj(Obj&)
(for which it is wrong).
You might SFINAE that constructor,
template<typename P>
requires (std::is_constructible_v<std::string, P>)
Obj(P&& param): name{std::forward<P>(param)} { }
or add extra overloads
Obj(Obj&&) = default;
Obj(Obj&) = default; // To fix the issue
Obj(const Obj&) = default;
or even simpler, as you don't need template here:
explicit Obj(std::string name): name{std::move(name)} { }