How to implement a factory with multiple switches?

I want to implement a factory function to create objects. My object template is as follows:

template <typename TA, typename TB> struct MyImpl : public MyInterface { // content }; 

and my factory is as follows:

 MyInterface* factory(char ta, char tb) { if(ta == 'c' && tb == 'c') { return new MyImpl<char, char>(); } if(ta == 'c' && tb == 's') { return new MyImpl<char, short>(); } if(ta == 's' && tb == 'c') { return new MyImpl<short, char>(); } // and so on .... } 

The factory function should accept non-static char ( ta , tb ) data, since it cannot be determined at compile time, and I think this whole point is factory. In fact, ta and tb read from a file (or network).

I want a simpler solution to avoid the annoying two-tier switch.

I think my question is similar to how-would-one-write-a-meta-if-else-if-in-c , except that I cannot use static parameters.

Perhaps I just need to drop the C macros and use some macro tricks to compress my current code?

Thanks in advance!

UPDATE

Reply to @Rob:

My actual code would be more complex with many other things in it, and it would be harder to read and not be related in many aspects. I am trying to get the pseudocode correctly. If there is any problem, please let me know :-).

Reply to @Dynguss:

My problem is that, in my actual implementation, the factory (ta, tb) parameters would be large in the range, for example 10 X ta and 20 X tb, and the combination of ta and tb would be very long in rows, and hard to maintain. Therefore, I need at least some way to facilitate the combination.

+7
source share
3 answers

Here is an idea:

 template <typename T> MyInterface * factroy(char t) { if (t == 'c') { return MyImpl<T, char>(); } if (t == 's') { return MyImpl<T, short>(); } // ... } MyInterface * factory(char ta, char tb) { if (ta == 'c') { return factroy<char>(tb); } if (ta == 's') { return factroy<short>(tb); } // ... } 

With variation templates, this template can be expanded to any number of type arguments - for example:

 struct Base { virtual ~Base() = default; }; template <typename A, typename B, typename C> struct Foo : Base { }; #include <tuple> template <typename ...Args> constexpr Base * factory(std::tuple<Args...>) { return new Foo<Args...>; } template <typename ...Args, typename ...Char> constexpr Base * factory(std::tuple<Args...>, char t, Char ... ts) { return t == 'c' ? make(std::tuple<char, Args...>(), ts...) : t == 's' ? make(std::tuple<short int, Args...>(), ts...) : t == 'i' ? make(std::tuple<int, Args...>(), ts...) : t == 'l' ? make(std::tuple<long int, Args...>(), ts...) : nullptr; } 

Usage: auto p = factory(std::tuple<>(), 'c', 's', 'l');

+13
source

If you can split the Impl constructor into a new Impl (new InnerImpl), then there is the possibility of a very complex solution that replaces the switches with a card:

  struct Creator { virtual ~Creator(){}; virtual Interface *create(InterfaceInner *) = 0; virtual InterfaceInner *createInner() = 0; } std::Map<char, Creator *> creatorMap; template<char T> struct Factory { Factory() { creatorMap.insert(T, &this->creator); } } template<> struct Factory<'s'> { struct ShortCreator : public Creator { virtual Interface *create(InterfaceInner *inner) {return new Impl<short>(inner);} virtual InterfaceInner *createInner(return new ImplInner<short>()); } creator; } Factory<'s'> shortFactory; Factory<'c'> charFactory; creatorMap[ta].create(creatorMap[tb].createInner()); 
0
source

What about:

 MyInterface* factory(char ta, char tb) { switch( ta << 8 | tb ) { case 'cc': return MyImpl<char, char>(); case 'cs': return MyImpl<char, short>(); case 'sc': return MyImpl<short, char>(); // and so on .... } } 

NOTE. This works fine on Intel / AMD x86 and x64, on a processor with different content (for example, PPC), you should change ta and tb as follows: switch( ta | tb << 8 ) .

0
source

All Articles