2016-06-21 2 views
2

Мой текущий код выглядит следующим образом: Code hereКак получить внутренний класс шаблона типа внешнего класса шаблона?

У меня есть шаблон ClassOuter и вложенного шаблона ClassInnerBase, где TypeD может быть любого типа TypeA, TypeB, TypeC и никакой другой. Кроме того, ClassInnerDerived должен наследовать от ClassInnerBase и реализовать virtual const int Method(int id) = 0;.

template<typename TypeA, typename TypeB, typename TypeC> 
class ClassOuter { 
public: 

    class ClassInnerBase { 
    public: 
     ClassInnerBase(int x) : 
       m_x(x) { 
     } 

     virtual const int Method(int id) = 0; 

    private: 
     int m_x; 
    }; 

    template<typename TypeD> 
    class ClassInnerDerived : public ClassInnerBase { 
    public: 
     ClassInnerDerived<TypeD>(const TypeD &object, int x) : 
       ClassInnerBase(x), m_object(object) { 

     } 

     // Implementation of ClassInnerBase::Method for type float 
     template<> 
     const int ClassInnerDerived<float>::Method(int id){ 
      return GetLookupID(id); 
     } 

     // Implementation of ClassInnerBase::Method for type double 
     template<> 
     const int ClassInnerDerived<double>::Method(int id){ 
      return GetLookupID(id); 
     } 


    private: 
     TypeD m_object; 
    }; 

    void DoSomething(const std::vector<ClassInnerBase> &inner_vec, int id); 

    const int GetLookupID(int id) const{ 
     return lookup[id]; 
    } 

private: 
    int lookup[100]; 
}; 

template<typename TypeA, typename TypeB, typename TypeC> 
void ClassOuter<TypeA, TypeB, TypeC>::DoSomething(const std::vector<ClassInnerBase> &inner_vec, int id){ 
    for(const auto &inner : inner_vec){ 
     inner.Method(id); 
    } 
} 


int main() 
{ 
    std::vector<typename ClassOuter<int, double, float>::ClassInnerBase> class_base_objects; 
    typename ClassOuter<int, double, float>::template ClassInnerDerived<float> class_inner_derived_object(0.2f, 1); 
    class_base_objects.push_back(class_inner_derived_object); 

    typename ClassOuter<int, double, float>::template DoSomething(class_base_objects, 1); 
} 

я в конечном итоге получаю ошибку:

g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out 
main.cpp:30:18: error: explicit specialization in non-namespace scope 'class ClassOuter<TypeA, TypeB, TypeC>::ClassInnerDerived<TypeD>' 
     template<> 
       ^

Я совсем застрял здесь и не знаю, как решить эту ошибку. Кроме того, есть ли какие-либо предложения/комментарии/улучшения в реализации ifself?

+0

вы бы лучше быть лучше в [код Review] (http://codereview.stackexchange.com/) для улучшения вашей реализации – Rakete1111

+2

@ Rakete1111 Нет, обзор кода * не * место для сломанного кода, так как оно вне темы. Он спросил на правильном сайте. – syb0rg

+0

@ syb0rg Я имел в виду только бит улучшения. Для фактической ошибки OP находится на правильном сайте – Rakete1111

ответ

0

Как ваш компилятор говорит, что вы не можете явно (полностью) специализировать внутренний класс класса шаблона. То, что вы делаете, еще хуже, поскольку вы пытаетесь специализировать один метод из внутреннего класса, что невозможно даже для не вложенных шаблонных классов ... Что вы можете сделать, это обмануть компилятор, добавив дополнительный параметр шаблона со значением по умолчанию к вашему внутреннему классу и частично специализировать весь внутренний класс. Это фактически позволит вам проверить, имеет ли параметр шаблона заданный тип, используя механизм sfinae (я тестировал, как в вашем примере, если внутренний параметр шаблона буквально двойной или плавающий, но вы можете аналогичным образом проверить, является ли он одним из внешних типов шаблонов а), например:

#include <iostream> 
#include <type_traits> 
#include <vector> 

template<typename TypeA, typename TypeB, typename TypeC> 
class ClassOuter { 
public: 

    class ClassInnerBase { 
    public: 
     ClassInnerBase(int x) : 
       m_x(x) { 
     } 

     virtual const int Method(int id) = 0; 

    private: 
     int m_x; 
    }; 

    template<typename TypeD, typename = void> 
    class ClassInnerDerived; 

    template<typename TypeD> 
    class ClassInnerDerived<TypeD, std::enable_if_t<std::is_same<TypeD, float>::value || std::is_same<TypeD, double>::value> >: public ClassInnerBase { 
    public: 
     // Implementation of ClassInnerBase::Method for type float 
     ClassInnerDerived(const TypeD &object, int x) : 
       ClassInnerBase(x), m_object(object) { 
     } 
     const int Method(int id){ 
      return GetLookupID(id); 
     } 
    private: 
     TypeD m_object; 
    }; 

    public: 

    //static void DoSomething(const std::vector<ClassInnerBase> &inner_vec, int id); 

    static const int GetLookupID(int id) { 
     return lookup[id]; 
    } 

private: 
    static int lookup[100]; 
}; 

template<typename TypeA, typename TypeB, typename TypeC> 
int ClassOuter<TypeA, TypeB, TypeC>::lookup[100]; 

/* 
template<typename TypeA, typename TypeB, typename TypeC> 
void ClassOuter<TypeA, TypeB, TypeC>::DoSomething(const std::vector<ClassInnerBase> &inner_vec, int id){ 
    for(const auto &inner : inner_vec){ 
     inner.Method(id); 
    } 
}*/ 


int main() 
{ 
std::vector<typename ClassOuter<int, double, float>::ClassInnerBase *> class_base_objects; 
    //typename ClassOuter<int, double, float>::template ClassInnerDerived<float> class_inner_derived_object(0.2f, 1); 
    class_base_objects.push_back(new ClassOuter<int, double, float>::ClassInnerDerived<float>(0.2f, 1)); //(class_inner_derived_object); 

    //typename ClassOuter<int, double, float>::template DoSomething(class_base_objects, 1); 
} 

Приведенный выше код, вероятно, не на самом деле делать то, что вы хотите, но я думаю, что это хорошая отправная точка ...