2011-12-13 23 views
7

Pracując nad własnym typ wymazywania iterator, pobiegłem do problemu gdzie kompilator (MSVC10) rozbił się z przepełnienie stosu na ten kod:kompilator przepełnienie stosu na kodzie szablonu

struct base {}; //In actual code, this is a template struct that holds data 
template<class category, class valuetype> 
    struct any; //In actual code, this is abstract base struct 
template<class basetype, class category, class valuetype> 
    struct from; //In actual code, this is function definitions of any 

template<class valuetype> 
struct any<void,valuetype> 
{ void a() {} }; 
template<class category, class valuetype> 
struct any 
    : public any<void,valuetype> //commenting this line makes it compile 
{ void b() {} };   

template<class basetype, class valuetype> 
struct from<basetype,void,valuetype> 
    : public base //commenting out _either_ of these makes it compile 
    , public any<void,valuetype> 
{ void c() {} }; 

int main() { 
    from<int, void, char> a; 
    a.a(); 
    a.c(); 
    any<int, char> b; 
    b.a(); 
    b.b(); 
    return 0; 
} 

Oczywiście mam usunąłem wszystko, co mogę, tam, gdzie pozostanie błąd. (Oryginalnym kodem było 780 wierszy) Usunięcie pozostałych parametrów szablonu powoduje kompilację kodu.

Pełny komunikat o błędzie:

main.cpp(23): fatal error C1063: compiler limit : compiler stack overflow 
    main.cpp(20) : see reference to class template instantiation 'from<basetype,void,valuetype>' being compiled 

IDEOne compiles it fine. Słyszałem, że MSVC zaimplementował dwuetapowe wyszukiwanie błędne, co wydaje się odpowiednie, ale nie wyjaśnia, dlaczego kompiluje się po usunięciu linii, która powoduje, że from dziedziczy po base. Czy ktoś może mnie nauczyć, dlaczego MSVC10 nie skompiluje tego? Co zrobiłem, czego powinienem unikać?

+0

Na co warto, GCC 4.6 kompiluje kod przykładowy bez kłopotów (na Linux/Debian/Sid/AMD64). Być może mógłbyś przejść na GCC (np. Jakiś wariant MinGW lub Cygwin ...)? –

+0

Prawdę mówiąc, wykonałem sporo debugowania za pośrednictwem IDEOne, ale moje polecenia-lin-fu i linux są słabe, więc Cygwin jest onieśmielający. Zaczynam się z tym bawić. –

+0

Masz klasę szablonów, która dziedziczy z samej siebie? Czy mogę to źle odczytać? – AJG85

Odpowiedz

1

Jako obejście, należy rozważyć wprowadzenie dodatkowego klasę pomiędzy niewykwalifikowanego any i specjalizacji z category = void:

template <class valuetype> 
class detail_void_any 
    : public any<void, valuetype> 
{ 
}; 


template<class category, class valuetype> 
class any 
    : public detail_void_any<valuetype> 
{ 
}; 

Poniższy pełny program powinien się skompilować bez błędu:

class base {};  // Data Holder (in reality it's templated, so required) 
template<class category, class valuetype> 
     class any; // Virtual Function Interface 
template<class basetype, class category, class valuetype> 
     class from; // Virtual Function Implementation 

template<class valuetype> 
class any<void,valuetype> 
{}; 


template <class valuetype> 
class detail_void_any 
    : public any<void, valuetype> 
{ 
}; 

template<class category, class valuetype> 
class any 
    : public detail_void_any<valuetype> 
{ 
}; 

template<class basetype, class valuetype> 
class from<basetype,void,valuetype> 
     : public base //commenting out _either_ of these makes it compile 
     , public any<void,valuetype> 
{}; //this is line 23, where the compiler crashes 

int main() {return 0;} 
+0

huh, zastanawiam się, dlaczego to działa. Dobre znalezisko. –

1

Dobrze poddaję się, ale udało się wygenerować ostrzeżenie:

template <typename T1, typename T2> 
class Any; // forward 

template <typename T2> 
class Any<void, T2> // partial spec of forward 
{}; 

template <typename T1, typename T2> 
class Any: // template definition 
    public Any<void, T2> // inherit from partial spec 
{}; 

template <typename T1, typename T2> 
class From : 
    public Any<int, T2>, // inherit definition 
    public Any<void, T2> // inherit definition or partial spec? 
    // with spec first we get fatal error C1063: compiler limit : compiler stack overflow (CRASH!) 
    // with definition first we get warning C4584: 'From<T1,T2>' : base-class 'Any<void,T2>' is already a base-class of 'Any<int,T2>' 
{}; 

int main() 
{ 
    return 0; 
} 
+0

Zauważ, że mój kod ma trzy klasy szablonów, 'Test' dziedziczy po' Cokolwiek 'i niepowiązanej klasie. 'Test' nie dziedziczy po' Cokolwiek '. Spróbuję jednak odwrócić kolejność dziedziczenia i sprawdzić, czy to coś naprawi. –

+0

Odwrócenie dziedziczenia 'Anywhere ' i niepowiązanego typu nie rozwiązuje problemu. Nie widzę żadnej prawdziwej różnicy między twoim kodem a moim ... –

+0

Zmieniłem nazwę klas i przestawiłem je, aby uczynić nieco bardziej oczywistym, dlaczego każda z klas jest wymagana i jak działają części. –

1

Najprostszy obejście: Wymienić:

template<class category, class valuetype> 
class any : public any<void, valuetype> 
{ 
}; 

z:

template<class valuetype, class category> 
class any : public any<void, valuetype> 
{ 
}; 
+0

Tyle tylko, że to nie działa dobrze. – Xeo

+0

@Xeo: faktycznie ... Wydaje się działać ... Dodałem funkcje członkowskie do weryfikacji. WTF? Dobre znalezisko ... –

+0

@Mooing: Nie powinno tak być, ponieważ musisz zmienić parametry szablonu również dla przypadku "void". – Xeo

Powiązane problemy