Template partial specialization
Would any one knows according to what rules code below doesn't compile?
template开发者_C百科 <class T>
struct B
{
typedef T type;
};
template<class T>
struct X
{
};
template<class T>
struct X<B<T>::type*>//HERE I'M PARTIALLY SPECIALIZING (WELL, TRYING TO...)
{
};
Please see comment inside the code.
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.
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.
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
"The argument list cannot be identical to the non-specialized argument list (it must specialize something)" see partial_specialization at en.cppreference.com
精彩评论