Переполнение стека компилятора в коде шаблона - PullRequest
7 голосов
/ 14 декабря 2011

Во время работы над собственным итератором стирания типов я столкнулся с проблемой, когда компилятор (MSVC10) потерпел крах с переполнением стека в этом коде:

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

Очевидно, я удалил все, что мог, где ошибка остается. (Ориентировочный код состоял из 780+ строк). Удаление оставшихся параметров шаблона приводит к компиляции кода.

Полное сообщение об ошибке:

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 прекрасно компилирует . Я слышал, что MSVC неправильно реализовал двухфазный поиск, что кажется уместным, но не объясняет, почему он компилируется, когда я удаляю строку, которая заставляет from наследовать от base. Может кто-нибудь научить меня, почему MSVC10 не скомпилирует это? Что я сделал, что мне следует избегать?

Ответы [ 3 ]

1 голос
/ 14 декабря 2011

В качестве обходного пути рассмотрите возможность введения дополнительного класса между неспециализированной any и специализацией с 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>
{
};

Следующая полная программа должна скомпилироваться без ошибок:

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;}
1 голос
/ 14 декабря 2011

Самый простой обходной путь: Заменить:

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

с:

template<class valuetype, class category>
class any : public any<void, valuetype>
{
};
1 голос
/ 14 декабря 2011

Хорошо, я сдаюсь, но мне удалось сгенерировать предупреждение:

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