2009-03-16 4 views
50

Я пытаюсь использовать typedef из подкласса в моем проекте, я выделил свою проблему в приведенном ниже примере.Недопустимое использование неполного типа

Кто-нибудь знает, где я иду не так?

template<typename Subclass> 
class A { 
    public: 
     //Why doesn't it like this? 
     void action(typename Subclass::mytype var) { 
      (static_cast<Subclass*>(this))->do_action(var); 
     } 
}; 

class B : public A<B> { 
    public: 
     typedef int mytype; 

     B() {} 

     void do_action(mytype var) { 
      // Do stuff 
     } 
}; 

int main(int argc, char** argv) { 
    B myInstance; 
    return 0; 
} 

Это выход я получаю:

[email protected]:~/Documents/LucadeStudios/experiments$ g++ -o test test.cpp 
test.cpp: In instantiation of ‘A<B>’: 
test.cpp:10: instantiated from here 
test.cpp:5: error: invalid use of incomplete type ‘class B’ 
test.cpp:10: error: forward declaration of ‘class B’ 

ответ

57

Причина заключается в том, что при создании экземпляра шаблона класса, все его заявления (не определения) его функций-членов также создаются. Шаблон класса создается именно тогда, когда требуется полное определение специализации. Это тот случай, когда он используется как базовый класс, например, как в вашем случае.

Так что же происходит, что A<B> инициализируются в

class B : public A<B> 

в какой момент B еще не полный типа (это после закрывающей скобки определения класса). Тем не менее, декларация A<B>::action «s требует B быть полным, так как он ползет в сфере его:

Subclass::mytype 

Что вам нужно сделать, это затягивание экземпляра до некоторой точки, в которой B является полным. Один из способов сделать это - изменить объявление action, чтобы сделать его шаблоном-членом.

template<typename T> 
void action(T var) { 
    (static_cast<Subclass*>(this))->do_action(var); 
} 

Это еще типобезопасным, потому что если var не правильный тип, проходя var в do_action потерпит неудачу.

+1

Я остановился на небольшой перестройке моего кода (из-за некоторых других связанных с этим проблем, которые я здесь не описал), но я протестировал этот подход, и он действительно устраняет проблему. Благодаря! – seanhodges

0

Вы должны использовать указатель или ссылку как соответствующий тип не известен в это время компилятор не может создать его экземпляр.

Вместо этого попробуйте:

void action(const typename Subclass::mytype &var) { 
      (static_cast<Subclass*>(this))->do_action(); 
    } 
+0

Я попытался изменить его на ссылку, а затем указатель, и ошибка все тот же. Я понимаю вашу точку зрения. – seanhodges

2

Вы выведете B из A<B>, поэтому первых, что компилятор делает, когда он видит определение класса B, чтобы попытаться создать экземпляр A<B>. Для этого необходимо знать B::mytype для параметра action. Но поскольку компилятор находится в процессе определения фактического определения B, он еще не знает этого типа, и вы получите сообщение об ошибке.

Один из способов обойти это было бы, чтобы объявить тип параметра в качестве другого параметра шаблона, вместо того, чтобы внутри производного класса:

template<typename Subclass, typename Param> 
class A { 
    public: 
     void action(Param var) { 
       (static_cast<Subclass*>(this))->do_action(var); 
     } 
}; 

class B : public A<B, int> { ... }; 
1

Не совсем то, что вы просили, но вы можете сделать Действие функции члена шаблона:

template<typename Subclass> 
class A { 
    public: 
     //Why doesn't it like this? 
     template<class V> void action(V var) { 
       (static_cast<Subclass*>(this))->do_action(); 
     } 
}; 

class B : public A<B> { 
    public: 
     typedef int mytype; 

     B() {} 

     void do_action(mytype var) { 
       // Do stuff 
     } 
}; 

int main(int argc, char** argv) { 
    B myInstance; 
    return 0; 
} 
22

Вы можете обойти это, используя класс качества:
Это требует, чтобы Вы создали specialsed класс черты для каждого действующего класса, который вы используете.

template<typename SubClass> 
class SubClass_traits 
{}; 

template<typename Subclass> 
class A { 
    public: 
     void action(typename SubClass_traits<Subclass>::mytype var) 
     { 
       (static_cast<Subclass*>(this))->do_action(var); 
     } 
}; 


// Definitions for B 
class B; // Forward declare 

template<> // Define traits for B. So other classes can use it. 
class SubClass_traits<B> 
{ 
    public: 
     typedef int mytype; 
}; 

// Define B 
class B : public A<B> 
{ 
    // Define mytype in terms of the traits type. 
    typedef SubClass_traits<B>::mytype mytype; 
    public: 

     B() {} 

     void do_action(mytype var) { 
       // Do stuff 
     } 
}; 

int main(int argc, char** argv) 
{ 
    B myInstance; 
    return 0; 
} 
Смежные вопросы