Is there a way to "bundle" template parameters together to avoid repetition?
I have several classes and functions that all use the same three template parameters. It is not unusual to have a function that uses each class/function once. The resulting code gets very messy very quickly. Is there a more concise way to write this code?
// ContextFactory is a pointer to functions that instantiate objects that are subtypes of MetricContext
template<typename VertexID, typename EdgeMembershipType, typename SetBitmap>
using ContextFactory = MetricContext <VertexID, EdgeMembershipType, SetBitmap> *(*)(const char *);
template<typename VertexID, typename EdgeMembershipType, typename SetBitmap>
static vector<ContextFactory<VertexID, EdgeMembershipType, SetBitmap>> buildCFList() {
vector<ContextFactory<VertexID, EdgeMembershipType, SetBitmap>> answer;
answer.push_back(MetricContext<VertexID, EdgeMembershipType, SetBitmap>::template make<NeoContext<VertexID, EdgeMembershipType, SetBitmap >>);
return answer;
};
Notice that almost half of this function is repetition of the string <VertexID, EdgeMembershipType, SetBitmap>>
, but each use of this string applies to a different class or function, so I don't think alias will work.
(If it helps, the purpose of this function is to create an array of pointers to functions that will create objects that are subtypes of MetricContext<VertexID, EdgeMembershipType, SetBitmap>>
A rather more specific approach than @Quentin's is to make your template depend on a single parameter - which is expected to have typedefs for VertexID
, EdgeMembershipType
, and SetBitmap
.
// ContextFactory is a pointer to functions that instantiate objects that are
// subtypes of MetricContext
template<typename Types>
using ContextFactory = MetricContext <Types> *(*)(const char *);
template<typename Types>
static vector<ContextFactory<Types>> buildCFList() {
vector<ContextFactory<Types>> answer;
answer.push_back(MetricContext<Types>::template make<NeoContext<Types>>);
return answer;
};
Note that when you want to actually use one of the typedefs, you will need to use for example: typename Types::VertexID
.
(Ideally you would come up with a better name than Types
for the template argument.)
Yes, this is possible. Let's define a little helper class to hold a list of types:
template <class... > struct pack { };
And a metafunction that instantiates a template with what's inside a pack
:
template <template <class... > class T, class P>
struct unpack_;
template <template <class... > class T, class... P>
struct unpack_<T, pack<P...>> {
using type = T<P...>;
};
template <template <class... > class T, class P>
using unpack = typename unpack_<T, P>::type;
And we can now store and use our parameter pack:
template <class A, class B, class C>
struct Foo { };
using Params = pack<int, float, double>;
unpack<Foo, Params> f; // f is a Foo<int, float, double>
See it live on Coliru
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With