Reputation: 23132
Suppose I have a class that can take a type and a varadic number of arguments:
template <typename T, typename... Args>
class B
{
T<Args...> x;
};
This class forms the basis for an alias type which will look like this:
template <typename... Args>
using AliasedType = B<T, Args...>;
But there are instances when the type T
is not a template, in which case the varadic pack will be of length 0. However, class B
will still attempt to declare an instance of this type with an empty set of template arguments, causing an error. So to get around this, I tried creating a template specialisation of B
which takes no varadic arguments at all:
template <typename T>
class B<T>
{
T x;
};
But this doesn't seem to work.
To illustrate the problem in a working example:
class A
{
};
template <typename T, typename... Args>
class B
{
T<Args...> x;
};
template <typename T>
class B<T>
{
T x;
};
main() {
B<A> a;
}
The output is:
error: ‘T’ is not a template T<Args...> x;
Why isn't this resolving to the specialised version that accepts non-template types? I'm sure I'm missing something really obvious here... It seems like an empty variadic template pack is not resolved as "nothing" as I had thought.
Upvotes: 1
Views: 212
Reputation: 1147
Here's an idea. It might not be optimal, but it works. First of all, you want your first parameter for B
to be a template template parameter (otherwise the error would even appear for valid arguments). For a non-template type, you could wrap the type in a template. This even works for basic types like double
:
template <template<typename...> class T, typename... Args>
class B
{
T<Args...> x;
};
template <typename T>
struct MakeTemplate {
template <typename...> using type = T;
};
template <typename T>
class Testclass {
T datamember;
};
main() {
B<MakeTemplate<double>::type > b1;
B<Testclass,int> b2;
}
This compiles fine, as you can see here. Might this be what you wanted? That said I just want to mention that you only need the whole logic if you need to access the template arguments of the supplied class for some reason besides declaring the member variable x
(in B
). Otherwise, you could just pass the fully specified class with all parameters filled in, i.e. B< Testclass<double> >
or B<double>
in which case B
would only need one template argument and that would always be a typename/class and not a template.
Upvotes: 3