Template partial specialization

后端 未结 3 1832
不知归路
不知归路 2020-12-11 08:47

Would any one knows according to what rules code below doesn\'t compile?

template 
struct B
{
    typedef T type;
};

template

        
相关标签:
3条回答
  • 2020-12-11 08:59

    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.

    0 讨论(0)
  • 2020-12-11 09:00

    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.

    0 讨论(0)
  • 2020-12-11 09:11

    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

    0 讨论(0)
提交回复
热议问题