Would any one knows according to what rules code below doesn\'t compile?
template
struct B
{
typedef T type;
};
template
You need to use typename
keyword as,
template<class T>
struct X<typename B<T>::type*>
{
};
It's because B<T>::type
is a dependent name. So typename
is required!
--
EDIT:
Even after putting typename
, it isn't compiling. I think it's because deduction of type T
in B<T>
from X<U>
is difficult, or possibly impossible, for the compiler. So I believe its non-deduced context.
See a similar example here and the discussion:
Template parameters in non-deduced contexts in partial specializations
However, if you change the specialization to this:
template<class T>
struct X<B<T> >
{
};
Then it becomes the deducible context, and so would compile.
How do you think that will work? The compiler will look to see if there is a class T somewhere that has a typedef "type" to your class?
It just won't. Even though it's a pointer.
Remember that presumably your B template is presumably specialised in places so that type is not always T*, but it can't deduce it with reverse engineering.
For those who did not understand my answer fully, what you are asking the compiler to do is find a class U such that B::type is the class you pass in as a parameter.
class Foo;
class Bar;
template<> struct B<Foo>
{
typedef int type;
};
template<> struct B<Bar>
{
typedef int type;
};
X<int*> // ambiguous, T is Foo or Bar?
It is difficult to know exactly why you are trying to do what you are. You can do a partial specialization on all pointers and then a total specialization on specific pointers, which could be implement in terms of another template.
Assuming you already added typename
as suggested by Nawaz.
The problem is exactly explained in the error message you encounter: "template parameter is not deducible in partial specialization B<T>::type*
. The problem is that B<T>::type
and T
is exactly the same for all types T
. Consider the following example:
class MyClass1 {};
typedef typename B<MyClass>::type MyClass2; //(*)
X<MyClass*> obj1;
X<MyClass2*> obj2;
The result of line (*)
is a type MyClass2 which is essentially MyClass1
. So, obj1
and obj2
should be objects of the same class. Now, which version of template X
should they use?
If you would expect the specialised version of X
, tell me if the answer should be the same if line (*)
is removed (and obviously obj2
as well). Still obj1
should be the specialised version of X
as line (*)
has nothing to do with it.
But now we expect the compiler to detect that some type can be potentially declared as B<T>::type
although we never do this. We expect the compiler to verify all possible template instantiations to check if there is no strange typedef in one of them.
I hope this clarifies why such specialisation cannot be handled by the compiler.
An alternative that might help
I believe your problem could be attacked by creating a trait class for explicitly marking types that should be handled in a special way. Something like this:
template <bool v>
struct boolean_value {
static const bool value=v;
};
template <typename T>
struct is_my_interesting_type : public boolean_value<false> {};
class MyClass {
...
};
template <>
struct is_my_interesting_type<MyClass> : public boolean_value<true> {};
template <typename T, bool special>
class InternalX {
... //generic version of your template X
};
template <typename T>
class InternalX<T,true> {
... //special version of your template X
};
template <typename T>
class X : public InternalX<T,is_my_interesting_type<T>::value> {};
Also, you might be interesting how it is done in boost library, in particular Boost.Type_Traits