首页 > 解决方案 > 哪种模式可以生成具有不同 Tor 参数的对象的实例化

问题描述

我想构建一个有或没有工具、移动底座和其他部件的机器人。由于我想自动化零件的配置,我有一个机器人类,其中零件作为模板参数

例如,在下面的代码中,只要我们使用与 ToolInterface 具有相同构造函数签名的工具,代码就会构建。它确实是用螺丝刀建造的,但不是用夹持器建造的。

#include <iostream>
#include <string>

class BaseRobot
{
public:
    BaseRobot(){};
};

class ToolInterface
{
public:
    ToolInterface(BaseRobot* _base, std::string _name):name{_name}{/*register _base*/};
    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 : public BaseRobot
{
protected:
    Tool* tool;
public:
    Robot():tool(construct<Tool>(this, "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(BaseRobot* _base, std::string _name):ToolInterface(_base, _name){};
};

class Gripper: public ToolInterface
{
public:
    Gripper(BaseRobot* _base, std::string _name, bool _reversed):
        ToolInterface(_base, _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;
}

这里有一些想法:

  1. 使用作为工具参数传递的 ToolConfig 结构。如果一个工具需要更多参数,则应该继承 ToolConfig 并将其转换为工具构造函数(见下文):该死,看起来既麻烦又丑陋!
  2. 强制继承 ToolInterface 类的 Ctor 签名:一些工具必须有不同的 Ctor 签名
  3. 使用可变参数模板将参数传递给模板:不合理,因为最后,我想要类似的东西template<class Tool1, class Tool2, class MobileBase, class Camera> class Robot

解决方案 1 看起来像

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;
};

你有一个神奇的模式来解决我的问题吗?我的模式错了吗?

标签: c++templatesdesign-patterns

解决方案


您也可以使用 tuple 代替 struct,虽然不理想,但这也可以:

#include <iostream>
#include <string>
#include <tuple>


class BaseRobot
{
public:
    BaseRobot() {};
};

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


template <typename T, typename ... Types, std::size_t ... Indices>
constexpr T* apply_impl(const std::tuple<Types...>& tuple, std::index_sequence<Indices...>)
{
    return new T(std::get<Indices>(tuple)...);
}


template <typename T, typename ... Types>
constexpr T* apply(const std::tuple<Types...>& tuple)
{
    return apply_impl<T>(tuple, std::index_sequence_for<Types...>());
}


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


template<class Tool>
class Robot : public BaseRobot
{
protected:
    Tool* tool;
public:
    template<class ...Args1>  //, class ...Args2> 
    Robot(std::tuple<Args1...> p1):  // , std::tuple<Args2...> p2):
    tool(construct<Tool>(p1))
    {   // <--- 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()
{
    using p1 = std::tuple<std::string>;
    Robot<Screwdriver> robot_screwdriver(p1{"sdvr"});

    return 0;
}

可以改进我同意。


推荐阅读