Templated factory based on the union of different enum class values












0














I'm trying to create a kind of Factory based on some enum values that the user can choose a compile time.



The main thing here is to create a kind of magic switch that works on different values of more than one kind of enum (kind of union of different union values, possibly with same value).



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


Is there an already kwown implementation pattern I can exploit here? I wouldn't like to re-invent the wheel.



Best would be something that compiles with C++11



[Edit] Some more info:



The factory should allow the creation of objects of different kind (that inherit from a specific base) in an efficient way. Ideally the user class that wants to add more objects can just create his enum and some classes that define the wanted behavior, and simply use the factory with these enums together with some other enums defined by other people.



Please ask for other clarifications if it's not clear










share|improve this question




















  • 2




    I somehow have the feeling that std::variant could be worth a look.
    – Scheff
    Nov 12 '18 at 10:10






  • 3




    Maybe you should clarify the question a bit - perhaps renaming classes, etc. to the intent. It is not really clear if this is an Abstract Factory or Concrete Factory pattern you aim at. Judging from the code you show and your naming it looks more like a Concrete Factory.
    – darune
    Nov 12 '18 at 10:12










  • @Scheff I thought about using it too, to replace the virtual method. I'd do that optionally.
    – svoltron
    Nov 12 '18 at 10:15










  • @darune yes, probably I'd better to clarify something. I'll edit the question
    – svoltron
    Nov 12 '18 at 10:15






  • 1




    Have you tried do to something really simple like std::vector< std::variant<A, B> > switch_type_one = {A::A1, A::A2, B::B1}; ? perhaps with some clever typing it could perhaps even be expanded to a map for looking up the construction parameters (although im not really sure how difficult that would be). What would be wrong with that type of solution ?
    – darune
    Nov 12 '18 at 12:17


















0














I'm trying to create a kind of Factory based on some enum values that the user can choose a compile time.



The main thing here is to create a kind of magic switch that works on different values of more than one kind of enum (kind of union of different union values, possibly with same value).



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


Is there an already kwown implementation pattern I can exploit here? I wouldn't like to re-invent the wheel.



Best would be something that compiles with C++11



[Edit] Some more info:



The factory should allow the creation of objects of different kind (that inherit from a specific base) in an efficient way. Ideally the user class that wants to add more objects can just create his enum and some classes that define the wanted behavior, and simply use the factory with these enums together with some other enums defined by other people.



Please ask for other clarifications if it's not clear










share|improve this question




















  • 2




    I somehow have the feeling that std::variant could be worth a look.
    – Scheff
    Nov 12 '18 at 10:10






  • 3




    Maybe you should clarify the question a bit - perhaps renaming classes, etc. to the intent. It is not really clear if this is an Abstract Factory or Concrete Factory pattern you aim at. Judging from the code you show and your naming it looks more like a Concrete Factory.
    – darune
    Nov 12 '18 at 10:12










  • @Scheff I thought about using it too, to replace the virtual method. I'd do that optionally.
    – svoltron
    Nov 12 '18 at 10:15










  • @darune yes, probably I'd better to clarify something. I'll edit the question
    – svoltron
    Nov 12 '18 at 10:15






  • 1




    Have you tried do to something really simple like std::vector< std::variant<A, B> > switch_type_one = {A::A1, A::A2, B::B1}; ? perhaps with some clever typing it could perhaps even be expanded to a map for looking up the construction parameters (although im not really sure how difficult that would be). What would be wrong with that type of solution ?
    – darune
    Nov 12 '18 at 12:17
















0












0








0


1





I'm trying to create a kind of Factory based on some enum values that the user can choose a compile time.



The main thing here is to create a kind of magic switch that works on different values of more than one kind of enum (kind of union of different union values, possibly with same value).



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


Is there an already kwown implementation pattern I can exploit here? I wouldn't like to re-invent the wheel.



Best would be something that compiles with C++11



[Edit] Some more info:



The factory should allow the creation of objects of different kind (that inherit from a specific base) in an efficient way. Ideally the user class that wants to add more objects can just create his enum and some classes that define the wanted behavior, and simply use the factory with these enums together with some other enums defined by other people.



Please ask for other clarifications if it's not clear










share|improve this question















I'm trying to create a kind of Factory based on some enum values that the user can choose a compile time.



The main thing here is to create a kind of magic switch that works on different values of more than one kind of enum (kind of union of different union values, possibly with same value).



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


Is there an already kwown implementation pattern I can exploit here? I wouldn't like to re-invent the wheel.



Best would be something that compiles with C++11



[Edit] Some more info:



The factory should allow the creation of objects of different kind (that inherit from a specific base) in an efficient way. Ideally the user class that wants to add more objects can just create his enum and some classes that define the wanted behavior, and simply use the factory with these enums together with some other enums defined by other people.



Please ask for other clarifications if it's not clear







c++ templates enums factory template-meta-programming






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 12 '18 at 10:25

























asked Nov 12 '18 at 10:01









svoltron

697




697








  • 2




    I somehow have the feeling that std::variant could be worth a look.
    – Scheff
    Nov 12 '18 at 10:10






  • 3




    Maybe you should clarify the question a bit - perhaps renaming classes, etc. to the intent. It is not really clear if this is an Abstract Factory or Concrete Factory pattern you aim at. Judging from the code you show and your naming it looks more like a Concrete Factory.
    – darune
    Nov 12 '18 at 10:12










  • @Scheff I thought about using it too, to replace the virtual method. I'd do that optionally.
    – svoltron
    Nov 12 '18 at 10:15










  • @darune yes, probably I'd better to clarify something. I'll edit the question
    – svoltron
    Nov 12 '18 at 10:15






  • 1




    Have you tried do to something really simple like std::vector< std::variant<A, B> > switch_type_one = {A::A1, A::A2, B::B1}; ? perhaps with some clever typing it could perhaps even be expanded to a map for looking up the construction parameters (although im not really sure how difficult that would be). What would be wrong with that type of solution ?
    – darune
    Nov 12 '18 at 12:17
















  • 2




    I somehow have the feeling that std::variant could be worth a look.
    – Scheff
    Nov 12 '18 at 10:10






  • 3




    Maybe you should clarify the question a bit - perhaps renaming classes, etc. to the intent. It is not really clear if this is an Abstract Factory or Concrete Factory pattern you aim at. Judging from the code you show and your naming it looks more like a Concrete Factory.
    – darune
    Nov 12 '18 at 10:12










  • @Scheff I thought about using it too, to replace the virtual method. I'd do that optionally.
    – svoltron
    Nov 12 '18 at 10:15










  • @darune yes, probably I'd better to clarify something. I'll edit the question
    – svoltron
    Nov 12 '18 at 10:15






  • 1




    Have you tried do to something really simple like std::vector< std::variant<A, B> > switch_type_one = {A::A1, A::A2, B::B1}; ? perhaps with some clever typing it could perhaps even be expanded to a map for looking up the construction parameters (although im not really sure how difficult that would be). What would be wrong with that type of solution ?
    – darune
    Nov 12 '18 at 12:17










2




2




I somehow have the feeling that std::variant could be worth a look.
– Scheff
Nov 12 '18 at 10:10




I somehow have the feeling that std::variant could be worth a look.
– Scheff
Nov 12 '18 at 10:10




3




3




Maybe you should clarify the question a bit - perhaps renaming classes, etc. to the intent. It is not really clear if this is an Abstract Factory or Concrete Factory pattern you aim at. Judging from the code you show and your naming it looks more like a Concrete Factory.
– darune
Nov 12 '18 at 10:12




Maybe you should clarify the question a bit - perhaps renaming classes, etc. to the intent. It is not really clear if this is an Abstract Factory or Concrete Factory pattern you aim at. Judging from the code you show and your naming it looks more like a Concrete Factory.
– darune
Nov 12 '18 at 10:12












@Scheff I thought about using it too, to replace the virtual method. I'd do that optionally.
– svoltron
Nov 12 '18 at 10:15




@Scheff I thought about using it too, to replace the virtual method. I'd do that optionally.
– svoltron
Nov 12 '18 at 10:15












@darune yes, probably I'd better to clarify something. I'll edit the question
– svoltron
Nov 12 '18 at 10:15




@darune yes, probably I'd better to clarify something. I'll edit the question
– svoltron
Nov 12 '18 at 10:15




1




1




Have you tried do to something really simple like std::vector< std::variant<A, B> > switch_type_one = {A::A1, A::A2, B::B1}; ? perhaps with some clever typing it could perhaps even be expanded to a map for looking up the construction parameters (although im not really sure how difficult that would be). What would be wrong with that type of solution ?
– darune
Nov 12 '18 at 12:17






Have you tried do to something really simple like std::vector< std::variant<A, B> > switch_type_one = {A::A1, A::A2, B::B1}; ? perhaps with some clever typing it could perhaps even be expanded to a map for looking up the construction parameters (although im not really sure how difficult that would be). What would be wrong with that type of solution ?
– darune
Nov 12 '18 at 12:17














1 Answer
1






active

oldest

votes


















2














Something like this might suit your needs (using void* for not having to introduce a base class, leaving adjustment to you...):



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


Usage:



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;


On my machine, printed happily:



hello
10.12
7





share|improve this answer





















  • yep, that seems a cool solution. I was looking for something in C++11, but at least this is an idea that works :)
    – svoltron
    Nov 12 '18 at 13:32










  • I've just noticed that this solution however does not fit exactly what I was looking for. Basically I would need something like Switcher<all my enums and input types> switcher(myInputs); switcher(A::A1); switcher(A::A2); so, just one declaration that works for all the enums
    – svoltron
    Nov 12 '18 at 13:40






  • 1




    @svoltron It works for any arbitrary number of enums - note the B::B1 being included in the demo; whichever enums you want to use, all is configured via the creator instantiations you provide as template arguments to the switcher...
    – Aconcagua
    Nov 12 '18 at 13:57






  • 1




    @svoltron I think the index sequence is the only C++14 feature I used. You might rebuild it yourself, there's more than one single answer for, e. g. this one. Similar, going a bit more into details.
    – Aconcagua
    Nov 12 '18 at 14:05






  • 1




    @svoltron If you don't like the if constexpr, make an ordinary if from. I used it mainly for assuring that the if is resolved at compile time - but as the expression is constant anyway, chances are that the compiler will do so even without constexpr...
    – Aconcagua
    Nov 12 '18 at 17:12











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53259767%2ftemplated-factory-based-on-the-union-of-different-enum-class-values%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









2














Something like this might suit your needs (using void* for not having to introduce a base class, leaving adjustment to you...):



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


Usage:



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;


On my machine, printed happily:



hello
10.12
7





share|improve this answer





















  • yep, that seems a cool solution. I was looking for something in C++11, but at least this is an idea that works :)
    – svoltron
    Nov 12 '18 at 13:32










  • I've just noticed that this solution however does not fit exactly what I was looking for. Basically I would need something like Switcher<all my enums and input types> switcher(myInputs); switcher(A::A1); switcher(A::A2); so, just one declaration that works for all the enums
    – svoltron
    Nov 12 '18 at 13:40






  • 1




    @svoltron It works for any arbitrary number of enums - note the B::B1 being included in the demo; whichever enums you want to use, all is configured via the creator instantiations you provide as template arguments to the switcher...
    – Aconcagua
    Nov 12 '18 at 13:57






  • 1




    @svoltron I think the index sequence is the only C++14 feature I used. You might rebuild it yourself, there's more than one single answer for, e. g. this one. Similar, going a bit more into details.
    – Aconcagua
    Nov 12 '18 at 14:05






  • 1




    @svoltron If you don't like the if constexpr, make an ordinary if from. I used it mainly for assuring that the if is resolved at compile time - but as the expression is constant anyway, chances are that the compiler will do so even without constexpr...
    – Aconcagua
    Nov 12 '18 at 17:12
















2














Something like this might suit your needs (using void* for not having to introduce a base class, leaving adjustment to you...):



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


Usage:



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;


On my machine, printed happily:



hello
10.12
7





share|improve this answer





















  • yep, that seems a cool solution. I was looking for something in C++11, but at least this is an idea that works :)
    – svoltron
    Nov 12 '18 at 13:32










  • I've just noticed that this solution however does not fit exactly what I was looking for. Basically I would need something like Switcher<all my enums and input types> switcher(myInputs); switcher(A::A1); switcher(A::A2); so, just one declaration that works for all the enums
    – svoltron
    Nov 12 '18 at 13:40






  • 1




    @svoltron It works for any arbitrary number of enums - note the B::B1 being included in the demo; whichever enums you want to use, all is configured via the creator instantiations you provide as template arguments to the switcher...
    – Aconcagua
    Nov 12 '18 at 13:57






  • 1




    @svoltron I think the index sequence is the only C++14 feature I used. You might rebuild it yourself, there's more than one single answer for, e. g. this one. Similar, going a bit more into details.
    – Aconcagua
    Nov 12 '18 at 14:05






  • 1




    @svoltron If you don't like the if constexpr, make an ordinary if from. I used it mainly for assuring that the if is resolved at compile time - but as the expression is constant anyway, chances are that the compiler will do so even without constexpr...
    – Aconcagua
    Nov 12 '18 at 17:12














2












2








2






Something like this might suit your needs (using void* for not having to introduce a base class, leaving adjustment to you...):



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


Usage:



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;


On my machine, printed happily:



hello
10.12
7





share|improve this answer












Something like this might suit your needs (using void* for not having to introduce a base class, leaving adjustment to you...):



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


Usage:



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;


On my machine, printed happily:



hello
10.12
7






share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 12 '18 at 13:17









Aconcagua

11.7k32143




11.7k32143












  • yep, that seems a cool solution. I was looking for something in C++11, but at least this is an idea that works :)
    – svoltron
    Nov 12 '18 at 13:32










  • I've just noticed that this solution however does not fit exactly what I was looking for. Basically I would need something like Switcher<all my enums and input types> switcher(myInputs); switcher(A::A1); switcher(A::A2); so, just one declaration that works for all the enums
    – svoltron
    Nov 12 '18 at 13:40






  • 1




    @svoltron It works for any arbitrary number of enums - note the B::B1 being included in the demo; whichever enums you want to use, all is configured via the creator instantiations you provide as template arguments to the switcher...
    – Aconcagua
    Nov 12 '18 at 13:57






  • 1




    @svoltron I think the index sequence is the only C++14 feature I used. You might rebuild it yourself, there's more than one single answer for, e. g. this one. Similar, going a bit more into details.
    – Aconcagua
    Nov 12 '18 at 14:05






  • 1




    @svoltron If you don't like the if constexpr, make an ordinary if from. I used it mainly for assuring that the if is resolved at compile time - but as the expression is constant anyway, chances are that the compiler will do so even without constexpr...
    – Aconcagua
    Nov 12 '18 at 17:12


















  • yep, that seems a cool solution. I was looking for something in C++11, but at least this is an idea that works :)
    – svoltron
    Nov 12 '18 at 13:32










  • I've just noticed that this solution however does not fit exactly what I was looking for. Basically I would need something like Switcher<all my enums and input types> switcher(myInputs); switcher(A::A1); switcher(A::A2); so, just one declaration that works for all the enums
    – svoltron
    Nov 12 '18 at 13:40






  • 1




    @svoltron It works for any arbitrary number of enums - note the B::B1 being included in the demo; whichever enums you want to use, all is configured via the creator instantiations you provide as template arguments to the switcher...
    – Aconcagua
    Nov 12 '18 at 13:57






  • 1




    @svoltron I think the index sequence is the only C++14 feature I used. You might rebuild it yourself, there's more than one single answer for, e. g. this one. Similar, going a bit more into details.
    – Aconcagua
    Nov 12 '18 at 14:05






  • 1




    @svoltron If you don't like the if constexpr, make an ordinary if from. I used it mainly for assuring that the if is resolved at compile time - but as the expression is constant anyway, chances are that the compiler will do so even without constexpr...
    – Aconcagua
    Nov 12 '18 at 17:12
















yep, that seems a cool solution. I was looking for something in C++11, but at least this is an idea that works :)
– svoltron
Nov 12 '18 at 13:32




yep, that seems a cool solution. I was looking for something in C++11, but at least this is an idea that works :)
– svoltron
Nov 12 '18 at 13:32












I've just noticed that this solution however does not fit exactly what I was looking for. Basically I would need something like Switcher<all my enums and input types> switcher(myInputs); switcher(A::A1); switcher(A::A2); so, just one declaration that works for all the enums
– svoltron
Nov 12 '18 at 13:40




I've just noticed that this solution however does not fit exactly what I was looking for. Basically I would need something like Switcher<all my enums and input types> switcher(myInputs); switcher(A::A1); switcher(A::A2); so, just one declaration that works for all the enums
– svoltron
Nov 12 '18 at 13:40




1




1




@svoltron It works for any arbitrary number of enums - note the B::B1 being included in the demo; whichever enums you want to use, all is configured via the creator instantiations you provide as template arguments to the switcher...
– Aconcagua
Nov 12 '18 at 13:57




@svoltron It works for any arbitrary number of enums - note the B::B1 being included in the demo; whichever enums you want to use, all is configured via the creator instantiations you provide as template arguments to the switcher...
– Aconcagua
Nov 12 '18 at 13:57




1




1




@svoltron I think the index sequence is the only C++14 feature I used. You might rebuild it yourself, there's more than one single answer for, e. g. this one. Similar, going a bit more into details.
– Aconcagua
Nov 12 '18 at 14:05




@svoltron I think the index sequence is the only C++14 feature I used. You might rebuild it yourself, there's more than one single answer for, e. g. this one. Similar, going a bit more into details.
– Aconcagua
Nov 12 '18 at 14:05




1




1




@svoltron If you don't like the if constexpr, make an ordinary if from. I used it mainly for assuring that the if is resolved at compile time - but as the expression is constant anyway, chances are that the compiler will do so even without constexpr...
– Aconcagua
Nov 12 '18 at 17:12




@svoltron If you don't like the if constexpr, make an ordinary if from. I used it mainly for assuring that the if is resolved at compile time - but as the expression is constant anyway, chances are that the compiler will do so even without constexpr...
– Aconcagua
Nov 12 '18 at 17:12


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53259767%2ftemplated-factory-based-on-the-union-of-different-enum-class-values%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







這個網誌中的熱門文章

Xamarin.form Move up view when keyboard appear

Post-Redirect-Get with Spring WebFlux and Thymeleaf

Anylogic : not able to use stopDelay()