Reputation: 21514
Consider this piece of code creating, based on a condition, a different class instance through a std::make_shared
. Note that the two possible classes used (Child1
and Child2
) are having the same construction parameters.
class Base
{
public:
Base( int param )
{
}
};
class Child1 : public Base
{
public:
using Base::Base;
};
class Child2 : public Base
{
public:
using Base::Base;
};
std::shared_ptr<Base> getPtr( bool cond, int param )
{
if ( cond )
return std::make_shared<Child1>(param);
else
return std::make_shared<Child2>(param);
}
int main(int argc, char* argv[]) {
bool permissive = ...;
Test::getPtr( permissive, argc );
return 0;
}
Note that permissive
is unknown at compilation time.
Is there a way to factorize argument list management in getPtr
function with something like:
return std::make_shared<cond?Child1:Child2>(param);
This obviously does not compile but I could not find a way to make something similar work even using templates...
Upvotes: 1
Views: 216
Reputation: 37587
Here is generalized solution i came up with while figuring similar problem. Works with several classes and several forwarded arguments. Uses indexing instead of branching. Does not suffer from code duplication.
#include <array>
#include <memory>
#include <utility>
#include <cstddef>
template<typename T, typename... Args>
::std::shared_ptr<Base> Impl(Args &&... args)
{
return ::std::make_shared<T>(::std::forward<Args>(args)...);
}
template<typename... T, typename... Args>
::std::shared_ptr<Base> Make(::std::size_t const index, Args &&... args)
{
return ::std::array{Impl<T, Args...>...}[index](::std::forward<Args>(args)...);
}
...
int main()
{
auto cond{true};
auto p_base{Make<Child1, Child2>(cond, 42)};
}
Upvotes: 0
Reputation: 217478
With tuple, you might have only one parameter, so, something like:
std::shared_ptr<Base> getPtr(bool cond, /*lot_of_params*/)
{
std::tuple t{lot_of_params};
if (cond)
return std::apply([](auto&&... args){return std::make_shared<Child1>(args...);}, t);
else
return std::apply([](auto&&... args){return std::make_shared<Child2>(args...);}, t);
}
Upvotes: 2
Reputation: 21514
Best solution I could find to avoid duplicating code managing parameters is
class Helper
{
public:
int param;
template<class T>
std::shared_ptr<Base> create( int param )
{
return std::make_shared<T>(param);
}
};
std::shared_ptr<Base> getPtr( bool cond, int param )
{
Helper helper{param};
return cond ? helper.create<Child1>() : helper.create<Child2>();
}
Upvotes: 2