Reputation: 17177
I have a codebase with a lot of enums associated functions that return singletons. Their names are formulaic:
enum Foo {...};
const MySingleton* Foo_Singleton();
enum Bar {...};
const MySingleton* Bar_Singleton();
...
Is it possible to write a C++ template that would choose the right getter function name without explicitly listing all the options?
template <typename EnumT>
inline const MySingleton* Get() {
return EnumT ## _Singleton();
}
I know I'm using a nonsensical preprocessor directive here, but I hope it communicates my aim. I know I could write an overload for each enum, but there are a lot of them and it would be a pain to maintain, so I would prefer to avoid that solution.
Upvotes: 3
Views: 170
Reputation: 13988
The easiest way would be to change your naming policy:
enum Foo {...};
const MySingleton* Get(Foo); // instead of const MySingleton* Foo_Singleton();
enum Bar {...};
const MySingleton* Get(Bar); // instead of const MySingleton* Bar_Singleton();
The mechanism involved is called tag dispatching. Now you could get appropriate singleton instance by simple:
Get(Foo{});
Upvotes: 4
Reputation: 21594
I doubt a solution mixing macros and template will be possible here.
A template-based solution that will work, but will require a wrapper function to be declared for every type.
First, define those functions:
const MySingleton* GetSingleton( Foo* var ) { return Foo_Singleton(); }
const MySingleton* GetSingleton( Bar* var ) { return Bar_Singleton(); }
Then just do:
template <typename EnumT>
inline const MySingleton* Get() {
EnumT e;
return GetSingleton( &e );
}
And then the appropriate GetSingleton
will be picked up by the compiler, depending on EnumT
.
Note, you can use a macro to declare the function, but I'm not sure it will be very useful:
#define DECLARE_WRAPPER(TYPE) const MySingleton* GetSingleton( TYPE* var ) { return TYPE##_Singleton(); }
DECLARE_WRAPPER( Foo )
DECLARE_WRAPPER( Bar )
Upvotes: 1
Reputation: 6046
One of the possibilities:
// template specification (to be specialized)
template <typename EnumT>
const MySingleton* Get();
#define JOIN_IMPL(a, b) a ## b
#define JOIN(a, b) JOIN_IMPL(a, b)
// template specialization for particular enum
#define DEFINE_GET_SINGLETON(EnumT) \
template<> \
inline const MySingleton* Get<EnumT>() { \
return JOIN(EnumT, _Singleton)(); \
}
DEFINE_GET_SINGLETON(Foo)
DEFINE_GET_SINGLETON(Bar)
By using macros you can save some typing (at the expense of debugging - most debuggers cannot step through macros).
Upvotes: 2