Reputation: 6606
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>>
Upvotes: 4
Views: 397
Reputation: 7804
if you're using C++11, you can make use of std::tuple to combine the variables into one.
A simpler example to understand the same can be
template <typename A, typename B, typename C>
void fn() {
typedef std::tuple<A,B,C> myTuple;
myTuple tpl;
cout<<sizeof(std::get<0>(tpl))<<endl;;
cout<<sizeof(std::get<1>(tpl))<<endl;
cout<<sizeof(std::get<2>(tpl))<<endl;
}
int main() {
fn<int,char,long>();
return 0;
}
For the problem specific to your question, you can create vectors of tuple as
template <typename A, typename B, typename C>
void fn() {
using mycomb = std::tuple<A,B,C>;
vector<mycomb> v1;
v1.push_back(make_tuple(10,'c',20.0));
}
In this way, you don't need to repeat the same. Tuple getter functions are bit awkward at first. The cout
examples above demonstrates how to access tuple parameters
Hope this helps
Upvotes: 1
Reputation: 29017
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.)
Upvotes: 5
Reputation: 63144
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>
Upvotes: 4