Templated factory based on the union of different enum class values











up vote
0
down vote

favorite
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




















  • 2




    I somehow have the feeling that std::variant could be worth a look.
    – Scheff
    Nov 12 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 at 10:12










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










  • @darune yes, probably I'd better to clarify something. I'll edit the question
    – svoltron
    Nov 12 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 at 12:17

















up vote
0
down vote

favorite
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




















  • 2




    I somehow have the feeling that std::variant could be worth a look.
    – Scheff
    Nov 12 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 at 10:12










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










  • @darune yes, probably I'd better to clarify something. I'll edit the question
    – svoltron
    Nov 12 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 at 12:17















up vote
0
down vote

favorite
1









up vote
0
down vote

favorite
1






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 at 10:25

























asked Nov 12 at 10:01









svoltron

697




697








  • 2




    I somehow have the feeling that std::variant could be worth a look.
    – Scheff
    Nov 12 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 at 10:12










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










  • @darune yes, probably I'd better to clarify something. I'll edit the question
    – svoltron
    Nov 12 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 at 12:17
















  • 2




    I somehow have the feeling that std::variant could be worth a look.
    – Scheff
    Nov 12 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 at 10:12










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










  • @darune yes, probably I'd better to clarify something. I'll edit the question
    – svoltron
    Nov 12 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 at 12:17










2




2




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




I somehow have the feeling that std::variant could be worth a look.
– Scheff
Nov 12 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 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 at 10:12












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




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












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




@darune yes, probably I'd better to clarify something. I'll edit the question
– svoltron
Nov 12 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 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 at 12:17














1 Answer
1






active

oldest

votes

















up vote
2
down vote



accepted










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








up vote
2
down vote



accepted










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 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 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 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 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 at 17:12















up vote
2
down vote



accepted










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 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 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 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 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 at 17:12













up vote
2
down vote



accepted







up vote
2
down vote



accepted






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 at 13:17









Aconcagua

11.6k32142




11.6k32142












  • 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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







Popular posts from this blog

Bressuire

Vorschmack

Quarantine