Suppose I have the following template class that defines a nested class:
template <typename T>
struct foo {
struct bar { };
};
Suppose the environment I'm coding in also has the following helper class, which should be specialized for any type that needs special handling:
template <typename T>
struct maybeChangeType { using type = T; } /* default: same type */
How can I specialize maybeChangeType
for foo<T>::bar
? It's easy enough to specialize for, say, foo<int>::bar
, but foo
will be used with 100+ different T
so that's not really an option.
NOTE: Please read carefully before marking this question as a duplicate. This question is not asking how to specialize in general (e.g. Understanding templates in c++), or how to declare friends, or even how to declare friends of templates. It is asking how to declare a friend for a non-template nested member of a template class (as the title states).
Trying to define specializations in the "normal" way does not work because foo<T>::bar
is not a deducible context (bad sign: it needs typename
in front):
/* error: template parameters not deducible in partial specialization */
template <typename T>
struct maybeChangeType<typename foo<T>::bar>;
Declaring the specialization as a friend also produces compilation errors:
template <typename T>
struct foo {
struct bar {
/* errors:
* - class specialization must appear at namespace scope
* - class definition may not be declared a friend
*/
template <>
friend struct maybeChangeType<bar> { using type=T; };
};
};
The above errors make it clear that the actual definition of these friends has to be out of line:
template <typename T>
struct foo {
struct bar {
friend struct maybeChangeType<bar>;
};
};
But now we're back where we started: any attempt to define a specialization for foo<T>::bar
will fail because it uses bar
in a non-deducible context.
NOTE: I can work around the issue for functions by providing a friend overload inline, but that's no help for a class.
NOTE: I could work around the issue by moving the inner class out to namespace scope, but that would pollute the namespace significantly (lots of inner classes the user really has no business playing with) and complicate the implementation (e.g. they would no longer have access to private members of their enclosing class and the number of friend
declarations would proliferate).
NOTE: I understand why it would be dangerous/undesirable to allow arbitrary specialization of the name foo<T>::bar
(what if foo<T>
had using bar = T
for example), but in this case bar
really is a class (not even a template!) which foo really does define, so there shouldn't be any ODR hairiness or risk that the specialization would affect other (unintended) types.
Ideas?