Passing variadic class template's sub-classes to function that only accepts the base class (via parameter pack deduction/inference)
**I've gotten a few suggestions to make my function pure generic, which would work, but I'd prefer limiting the function to only accept Base and its children.
Having trouble making a function that can accept arguments of a variadic template class base type, while the function will actually be called with classes that derive from Base. I've tried a few things. Here's the general idea. Given:
template<typename... Args> struct Base {
std::tuple<Args...> data;
... //other stuff
};
struct DerivedA : Base<string, int> {
};
struct DerviedB : Base<bool, string, int> {
};
What's the correct way to create a function that does this:
string moosh_together(Base A, Base B) { //I only need access to Base's members
return get<0>(A.data) + get<1>(B.data);
}
main() {
DerivedA aThing;
get<0>(aThing.data) = "foo";
DerivedB bThing;
get<1>(bThing.data) = "bar'd";
cout << moosh_together(aThing, bThing) &开发者_如何转开发lt;< endl;
}
Output:
foobar'd
I've tried a few variations of the moosh_together function, none of which work. Leaving it as above generates a compiler error about missing template arguments. I'm unsure how to pass through to the function the template arguments that define DerivedA and DerivedB.
Other things I've tried (shotgun method):
string moosh_together(Base<> A, Base<> B) {}
//err: conversion from 'DerivedA' to non-scalar type 'Base<>' requested
template<Base<typename... Args> T1, Base<typename... Args> T2>
string moosh_together(T1 A, T2 B) {}
//err: expected paramter pack before '...'
template<Base<Args...> T1, Base<Args...> T2>
string moosh_together(T1 A, T2 B) {}
//err: 'Args' was not declared in this scope
Edit:
If you need both parameter packs, you can just put both in the template specification:
template<typename... ArgsA, typename... ArgsB>
string moosh_together(const Base<ArgsA...>& A, const Base<ArgsB...>& B) {
return get<0>(A.data) + get<1>(B.data);
}
This works because the parameter packs are inferred from arguments and not specified in a list. Naturally you can't have a class that depends on multiple parameter packs.
When you write: string moosh_together(Base A, Base B)
, ask yourself what Base
is. Base
is a class template, not a class type.
In other words, given:
template <typename T>
struct foo {};
foo<int>
and foo<float>
are two totally different types, that just so happened to be made from the same class template. They have no common base class, and you cannot refer to them simply as foo
anymore than you can refer to both int
and float
with a single type.
You could factor out the non-dependent parts of Base
:
struct Core
{
string name;
};
template <typename... Args>
struct Base : Core
{
// ...
};
And then refer to the Core
portions:
// pass by reference, to avoid unnecessary copying
string moosh_together(const Core& a, const Core& b);
Or just make the function totally generic:
template <typename BaseOne, typename BaseTwo>
string moosh_together(const BaseOne& a, const BaseTwo& b);
And say "if you have the necessary members, you can use this function".
Couldn't you create a base class in the inheritance hierarchy for Base
and pass that to the moosh_together()
function? (Low knowledge of c++ here)
I think the general expansion of this is
string moosh_together(Base<T1...> A1, Base<T2...> A2, ... Base<Tn...> An) {
return get<0>(A1.data) + get<1>(A2) + ... + get<n-1>(An.data);
}
This could be written as follows
template<int I>
string moosh_together() { return ""; }
template<int I, typename ...Base1Ty, typename ... Bases>
string moosh_together(Base<Base1Ty...> const& base1, Bases const&... bases) {
return get<I>(base1.data) + moosh_together<I+1>(bases...);
}
template<typename ... Bases>
string moosh_together(Bases const&... bases) {
return moosh_together<0>(bases...);
}
精彩评论