Templated factory based on the union of different enum class values
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
|
show 7 more comments
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
2
I somehow have the feeling thatstd::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 likestd::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
|
show 7 more comments
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
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
c++ templates enums factory template-meta-programming
edited Nov 12 '18 at 10:25
asked Nov 12 '18 at 10:01
svoltron
697
697
2
I somehow have the feeling thatstd::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 likestd::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
|
show 7 more comments
2
I somehow have the feeling thatstd::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 likestd::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
|
show 7 more comments
1 Answer
1
active
oldest
votes
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
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 theB::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 theif constexpr
, make an ordinaryif
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 withoutconstexpr
...
– Aconcagua
Nov 12 '18 at 17:12
|
show 2 more comments
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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
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 theB::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 theif constexpr
, make an ordinaryif
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 withoutconstexpr
...
– Aconcagua
Nov 12 '18 at 17:12
|
show 2 more comments
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
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 theB::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 theif constexpr
, make an ordinaryif
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 withoutconstexpr
...
– Aconcagua
Nov 12 '18 at 17:12
|
show 2 more comments
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
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
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 theB::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 theif constexpr
, make an ordinaryif
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 withoutconstexpr
...
– Aconcagua
Nov 12 '18 at 17:12
|
show 2 more comments
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 theB::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 theif constexpr
, make an ordinaryif
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 withoutconstexpr
...
– 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
|
show 2 more comments
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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