基于不同枚举类值的并集的模板化工厂

时间:2018-11-12 10:01:14

标签: c++ templates enums factory template-meta-programming

我试图根据用户可以选择编译时间的一些枚举值创建一种Factory。

这里的主要目的是创建一种魔术开关,该魔术开关可对一种以上的枚举(不同的并集值,可能具有相同的值的并集)的不同值起作用。

enum class A  {A1, A2, A3, A4};
enum class B  {B1, B2, B3, B4, B6, B7};

struct ObjectBase 
{
virtual void apply(char input) = 0;
};

template<A a, class... Args>
struct Object : ObjectBase;

template<>
struct Object<A::A1, int> : ObjectBase
{
Object(int i) i_(i) { }
void apply(char input) { /*do stuff with i_*/}
int i_;
}

template<>
struct Object<A::A2, int, double> : ObjectBase
{
Object(int i, double d) i_(i), d_(d) { }
void apply(char input) { /*do stuff with i_*/}
int i_;
double d_;
}


template<class V, V value>
struct Element 
{
};

template<class V, V first, V last>
struct AllElementWithin 
{
};

Switcher< Element<A,A1>, Element<A,A2>, 
  AllElementWithin<B, B1, B3> > switcher (2, 4.0);
// This should create a switch / lookup table that 
// initializes for instance Object<A::A1> with 2
// and Object<A::A2> with 2 and 4

char myInput = 'F';
ObjectBase* ob = switcher.create(A::A1); 
// This should return an ObjectBase* that points to a 
// Object<A1,int>

ob->apply(myInput);

这里是否存在我可以利用的已知实现模式?我不想重新发明轮子。

最好的是可以用C ++ 11编译的东西

[编辑]更多信息:

工厂应允许以有效的方式创建不同种类的对象(从特定基础继承)。理想情况下,想要添加更多对象的用户类可以只创建他的枚举和一些定义所需行为的类,然后将工厂与这些枚举以及其他人定义的其他枚举一起使用。

如果不清楚,请要求其他说明

1 个答案:

答案 0 :(得分:2)

类似这样的东西可能适合您的需求(使用void *无需引入基类,而需要您进行调整...):

template <typename T, typename SelType, SelType SelValue, typename ... Arguments>
class Creator
{
    std::tuple<Arguments...> arguments;

    template<size_t ... Indices>
    void* create(std::index_sequence<Indices...>)
    {
        return new T( (std::get<Indices>(arguments), ...) );
    }

public:
    Creator(Arguments ... arguments)
        : arguments(arguments...)
    { }

    using SelectorType = SelType;
    static SelType const selectorValue = SelValue;
    void* create()
    {
        return create(std::index_sequence_for<Arguments...>{});
    }
};

template<typename ... Creators>
class Switcher
{
    std::tuple<Creators ...> creators;

    template<typename T, size_t Index>//, typename First, typename ... Remaining>
    void* select(T selector)
    {
        if constexpr(Index < sizeof...(Creators))
        {
            if constexpr(std::is_same<T, typename std::tuple_element<Index, decltype(creators)>::type::SelectorType>::value)
            {
                if(selector == std::tuple_element<Index, decltype(creators)>::type::selectorValue)
                    return std::get<Index>(creators).create();
            }
            return select<T, Index + 1>(selector);
        }
        return nullptr;
    }

public:
    Switcher(Creators ... creators)
            : creators(creators...)
    { }

    template <typename T>
    void* create(T t)
    {
        return select<T, 0U>(t);
    }
};

用法:

Switcher switcher
(
        Creator<std::string, A, A::A1, char const*>("hello"),
        Creator<double, A, A::A2, double>(10.12),
        Creator<uint32_t, B, B::B1, unsigned int>(7U)
);

// just for demonstration purposes: don't care for the memory leaks...
std::cout << *(std::string*)switcher.create(A::A1) << std::endl;
std::cout << *(double*)switcher.create(A::A2) << std::endl;
std::cout << *(uint32_t*)switcher.create(B::B1) << std::endl;

在我的机器上,愉快地打印:

hello
10.12
7