Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Parameter pack and perfect forwarding

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

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)} { }

Demo

or add extra overloads

Obj(Obj&&) = default;
Obj(Obj&) = default; // To fix the issue
Obj(const Obj&) = default;

Demo

or even simpler, as you don’t need template here:

explicit Obj(std::string name): name{std::move(name)} { }

Demo

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading