2011-12-13 11 views
7

Mentre lavorava da sola cancellazione del tipo iteratore, mi sono imbattuto in un problema in cui il compilatore (MSVC10) si è schiantato con un overflow dello stack su questo codice:compilatore di overflow dello stack sul codice del modello

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; 
} 

Ovviamente, ho rimosso tutto ciò che posso dove rimane l'errore. (Il codice di orientamento era 780+ linee) La rimozione di eventuali parametri del modello rimanenti causa la compilazione del codice.

Il messaggio di errore completo è:

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. Ho sentito che MSVC ha implementato la ricerca in due fasi errata, il che sembra rilevante, ma non spiega il motivo per cui viene compilato quando rimuovo la riga che rende ereditato lo from da base. Qualcuno può insegnarmi perché MSVC10 non lo compilerà? Che cosa ho fatto che dovrei evitare?

+0

Per quello che vale, GCC 4.6 compila il codice di esempio, senza difficoltà (su Linux/Debian/Sid/AMD64). Forse potresti passare a GCC (ad esempio una variante MinGW o Cygwin ...)? –

+0

In realtà ho eseguito una buona parte del debugging tramite IDEOne, ma la mia linea di comando-fu e linux sono deboli, quindi Cygwin sta intimidendo. Sto iniziando a giocarci comunque. –

+0

Hai una classe template che eredita da se stessa? O sto leggendo questo sbagliato? – AJG85

risposta

1

Per risolvere il problema, considero l'introduzione di una classe aggiuntiva tra il non specializzato any e la specializzazione con 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> 
{ 
}; 

Il seguente programma completo deve essere compilato senza errori:

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

eh, chiediti perché funziona. Buona scoperta –

1

Beh mi arrendo ma sono riuscito a generare un avviso:

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

Nota che il mio codice ha tre classi template, 'Test' eredita solo da' Whatever ' e una classe non correlata. 'Test' non eredita da' Whatever '. Cercherò di invertire l'ordine di ereditarietà, e vedere se questo risolve qualsiasi cosa. –

+0

L'inversione dell'eredità di "Qualsiasi cosa " e il tipo non correlato non risolve il problema. Non riesco a vedere alcuna reale differenza tra il tuo codice e il mio ... –

+0

Ho rinominato le classi e le ho ridistribuite per rendere leggermente più ovvio il motivo per cui ciascuna delle classi è richiesta e come funzionano le parti. –

1

soluzione più semplice: sostituire:

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

con:

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

Tranne che questo non fa la cosa giusta. – Xeo

+0

@Xeo: in realtà ... Sembra funzionare ... Ho aggiunto le funzioni membro per verificare. WTF? Buona ricerca ... –

+0

@Mooing: Non dovrebbe farlo, dato che avresti bisogno di cambiare i parametri del template anche per il caso 'void'. – Xeo

Problemi correlati