mercredi 27 janvier 2021

Which pattern to generify instantiation of objects that have different Ctor arguments

I would like to construct a robot with or without a tool, a mobile base, and other parts. As I want to automatize the configuration of the parts, I have a class Robot with the parts as template arguments

For instance, in the code below, the code will build as long as we use tools that have the same constructor signature as ToolInterface. It does build with a Screwdriver but does not with a Gripper.

#include <iostream>
#include <string>

class ToolInterface
{
public:
    ToolInterface(std::string _name):name{_name}{};
    std::string name;
    bool param_1;
    char param_2;
};

template<class T, class... Args>
constexpr T* construct(Args... args)
{
    if constexpr (std::is_same<T, nullptr_t>::value)
    {
        return nullptr;
    }
    else
    {
        return new T(args...);
    }
};

template<class Tool>
class Robot
{
protected:
    Tool* tool;
public:
    Robot():tool(construct<Tool>("tool")){   // <--- here is my problem !!
        if constexpr (! std::is_same<Tool, nullptr_t>::value)
        {
            //do stuff on/with tool->param_1, tool->param_2, ...
            std::cout << "tool configured" << std::endl;
        }
        else
            std::cout << "no tool" << std::endl;
    };
};

class Screwdriver : public ToolInterface
{
public:
    Screwdriver(std::string _name):ToolInterface(_name){};
};

class Gripper : public ToolInterface
{
public:
    Gripper(std::string _name, bool _reversed):
        ToolInterface(_name)
        ,reversed{_reversed}{};
    bool reversed;
};

int main()
{
    Robot<Screwdriver> robot_screwdriver;
    Robot<nullptr_t> robot_null;
    //Robot<Gripper> robot_gripper;     //does not build

    return 0;
}

Here are some ideas :

  1. using a ToolConfig struct that is passed as argument of Tools. If a tool requires more arguments, one should subclass ToolConfig and cast it into the tool constructor (see below) : damn, that looks cumbersome and ugly !
  2. enforce inherited ToolInterface classes Ctor signature : some tools must have a diferent Ctor signature
  3. using a variadic template to pass args into the template : not reasonnable because in the end I want something like template<class Tool1, class Tool2, class MobileBase, class Camera> class Robot

solution 1 would look like

struct ToolConfig
{
    std::string name;
};
struct GripperConfig : public ToolConfig
{
    bool reversed;
};
class Gripper : public ToolInterface
{
public:
    Gripper(ToolConfig& _config):
        ToolInterface(_config)
        ,reversed{static_cast<GripperConfig&>(_config).reversed}{};
    bool reversed;
};

Do you have a magic pattern to solve my problem ? Is my pattern wrong ?

Aucun commentaire:

Enregistrer un commentaire