Reputation: 1015
I'm trying to create an alias to a template, rather than a type and I can't find the syntax to do it. Below is an example that demonstrates my problem. My guess is this is just something that can't be done, but I'm hoping someone can prove me wrong. If it can't be done, is there some underlying reason it doesn't make sense to do this, or is it just not implemented?
template <class S>
class Down;
template <class S>
class Up {
template <class S1>
using Opposite = Down<S1>;
};
template <class S>
class Down {
template <class S1>
using Opposite = Up<S1>;
};
template <template <typename> class Direction>
void oneDirection() {
//Call another function here that uses the template argument as a template
}
template <template <typename> class Direction>
void bothDirections() {
oneDirection<Direction>();
oneDirection<Direction::Opposite>(); //This doesn't compile
}
int main() {
bothDirections<Up>();
}
Upvotes: 2
Views: 175
Reputation: 9317
In Direction::Opposite
, Direction::
is a nested-name-specifier, and it can't indeed denote a class template (you'd need to give it the required template arguments to make it a template specialization).
I suppose one reason to not allow that form is that class templates can have partial or explicit specializations, which can provide different members from the primary template, so the compiler needs to work with a specific specialization to be able to know exactly what's available in there.
You can work around this by using traits to associate the two templates:
template<class> class Up { };
template<class> class Down { };
template<template<class> class Direction> struct Direction_traits;
template<> struct Direction_traits<Up>
{
template<class S1> using Opposite = Down<S1>;
};
template<> struct Direction_traits<Down>
{
template<class S1> using Opposite = Up<S1>;
};
template<template<class> class Direction>
void oneDirection() {
//Do something here
}
template<template<class> class Direction>
void bothDirections() {
oneDirection<Direction>();
oneDirection<Direction_traits<Direction>::template Opposite>();
}
int main() {
bothDirections<Up>();
}
However, keep in mind that Direction_traits<Up>::Opposite
is not the same template as Down
, at least not yet - the language rules may change in the future, more details in this answer and its comments.
This could cause problems if you want to get back to Up
from inside oneDirection<Direction_traits<Up>::Opposite>
using the traits - there won't be a trait specialization defined for the alias template. Things would need to get a bit more complicated to allow such use; a possible solution is outlined in the answer quoted above.
Upvotes: 3