Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bind make_shared with variadic template

I'm trying to write the following factory class, but I can't find the proper syntax:

template<class T, typename... TArgs>
class Factory {
 public:
  Factory(TArgs... args) {
    creator_ = std::bind(&std::make_shared<T, TArgs...>, args...);
    //      ^^^ some error around here
  }
  std::shared_ptr<T> Create() const {
    return creator_();
  }
 private:
  std::function<std::shared_ptr<T>()> creator_;
};

This is how I use the factory:

class Foo {
 public:
  Foo(bool value) {}
};
class Bar {
 public:
   Bar(const std::string& value) {}
};
Factory<Foo, bool> f1(true);
Factory<Bar, std::string> f2("string");

These are the errors I get when declaring f1 and f2:

error: no match for 'operator=' (operand types are 'std::function<std::shared_ptr<Foo>()>' and 'std::_Bind_helper<false, std::shared_ptr<Foo> (*)(bool&&), bool&>::type {aka std::_Bind<std::shared_ptr<Foo> (*(bool))(bool&&)>}')
   creator_ = std::bind(&std::make_shared<T, TArgs...>, args...);
            ^

error: no match for 'operator=' (operand types are 'std::function<std::shared_ptr<Bar>()>' and 'std::_Bind_helper<false, std::shared_ptr<Bar> (*)(std::basic_string<char>&&), std::basic_string<char, std::char_traits<char>, std::allocator<char> >&>::type {aka std::_Bind<std::shared_ptr<Bar> (*(std::basic_string<char>))(std::basic_string<char>&&)>}')
   creator_ = std::bind(&std::make_shared<T, TArgs...>, args...);
            ^

What is the correct syntax I must use with std::bind?

like image 770
ChronoTrigger Avatar asked Dec 25 '22 15:12

ChronoTrigger


1 Answers

std::make_shared is declared like this:

template< class T, class... Args >
shared_ptr<T> make_shared( Args&&... args );

As such, std::make_shared<T, TArgs...> will result in a function taking rvalue references, which won't bind to args.... A simple fix for this is to force it to take lvalue references by collapsing the reference:

creator_ = std::bind(&std::make_shared<T,TArgs&...>, args...);
//                                            ^

An alternative is to use a lambda instead, which is more readable:

creator_ = [=](){return std::make_shared<T>(args...);};
like image 138
TartanLlama Avatar answered Jan 05 '23 23:01

TartanLlama