c++ - 生成具有不同 Ctor 参数的对象实例化的模式

标签 c++ templates design-patterns

我想构建一个带或不带工具、移动底座和其他部件的机器人。因为我想自动化部件的配置,所以我有一个 Robot 类,其中部件作为模板参数

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

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

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

最佳答案

你也可以使用 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;
}

可以改进我同意。

关于c++ - 生成具有不同 Ctor 参数的对象实例化的模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65923586/

相关文章:

java - 决定将类设为静态

iphone - 是否可以让工厂类负责创建对象集合而不是一次创建一个对象

c++ - OpenGL 索引和数组纹理

c++ - "No Matching Constructor"尝试实例化模板类的对象时出错

function - 在 if 语句中使用函数 return 或在 go 模板中使用变量

c++ - C++ 中的通用模板

c++ - 如果单个 cpp 文件构建可执行文件

c++ - 以最佳方式从 system() 命令捕获标准输出

c++ - 为什么这不是函数模板的部分特化?

php - Laravel 上的存储库模式