Ошибка компилятора gcc 4.1.2 вложенных шаблонов

Я пытаюсь создать класс шаблона, чтобы изолировать пользователей от типа данных. Я бы предпочел использовать класс адаптера, но для изменения сигнатур функций требуется шаблон.

В приведенном ниже примере кода (не настоящий проект, а упрощенная версия для иллюстрации проблемы), в то время как в основной процедуре я могу использовать интерфейс ob_traits. Но когда я пытаюсь создать шаблон StructWrapper, который использует ob_traits в качестве базового класса, я получаю ошибки, и gcc не распознает созданный класс IntAdapter. Это компилируется в MSVC 8.0, но не работает в gcc 4.1.2 20070626 (Red Hat 4.1.2-14)

Итак, сначала два вопроса: вы понимаете, почему компиляция завершается с ошибками, указанными ниже?

Во-вторых, какие-либо предложения о том, как реализовать эту концепцию более простым способом?

    #include <iostream>

    template <typename T >
    struct ob_traits
    {
        ob_traits( T& param ) { value = param; };
        T value;
    };

    struct GeneralStructure
    {
        int a;
        GeneralStructure(int param):a(param){}
    };

    struct DifferentStructure
    {
        GeneralStructure hidden;
        DifferentStructure( int param ):hidden(param){};
    }
    ;

    /*template< typename T > struct ob_traits
    {
    };
    */
    template<> struct ob_traits< GeneralStructure >
    {
        struct IntAdapter
        {
            IntAdapter( GeneralStructure& valueParam ):value(valueParam){}
            GeneralStructure value;
            int& getValue() { return value.a; };
        };
    };

    template<> struct ob_traits< DifferentStructure >
    {
        struct IntAdapter
        {
            IntAdapter( DifferentStructure& valueParam):value( valueParam ){}
            DifferentStructure value;
            int& getValue( ){ return value.hidden.a; };
        };
        void dump()
        {
            DifferentStructure testLocal(44);
            IntAdapter local( testLocal );
            std::cout << local.getValue()<<std::endl;
        }
    };

    template <typename T > struct StructWrapper:public ob_traits< T >
    {
        StructWrapper(){};
    /*main.cpp:60: error: 'IntAdapter' was not declared in this scope
    main.cpp:60: error: expected `;' before 'inner'
    main.cpp:60: error: 'inner' was not declared in this scope
    */
        void dumpOuter(const T& tempParam) { IntAdapter inner(tempParam); inner.dump(); };
    /*
    main.cpp: In member function 'void StructWrapper<T>::dumpOuterFailsAsWell(const T&)':
    main.cpp:66: error: expected `;' before 'inner'
    main.cpp:66: error: 'inner' was not declared in this scope
    */
        void dumpOuterFailsAsWell(const T& tempParam) { ob_traits<T>::IntAdapter inner(tempParam); inner.dump(); };
    };

    int main(int argc, char* argv[])
    {
        GeneralStructure dummyGeneral(22);
        ob_traits<struct GeneralStructure >::IntAdapter test(dummyGeneral);
        DifferentStructure dummyDifferent(33);
        ob_traits<struct DifferentStructure >::IntAdapter test2(dummyDifferent);
        std::cout << "GeneralStructure: "<<test.getValue()<<std::endl;
        std::cout << "DifferentStructure: "<<test2.getValue()<<std::endl;
        ob_traits<struct DifferentStructure > test3;
        test3.dump();
    std::cout << "Test Templated\n";
    return 0;
    }

person Community    schedule 05.11.2008    source источник
comment
Аналогичная проблема с более кратким объяснением по адресу: stackoverflow.com/questions/11405/ проблема-шаблона-с-gcc   -  person Superpolock    schedule 06.11.2008
comment
Решение было найдено путем обновления двух строк: void dumpOuterFailsAsWell(const T& tempParam) { 'typename' ob_traits‹T›::IntAdapter inner(tempParam); внутренний.дамп(); }; };   -  person    schedule 06.11.2008


Ответы (3)


dumpOuter терпит неудачу, потому что IntAdapter необходимо квалифицировать (как в указанном вопросе). dumpOuterFailsAsWell терпит неудачу, потому что GCC выполняет синтаксический анализ этого кода, даже если он не завершен, и поэтому он должен знать, что это тип, который вы имеете в виду:

void dumpOuterWorks(const T& tempParam) 
{ 
   typename ob_traits<T>::IntAdapter inner(tempParam); 
   inner.dump(); 
}

Без typename здесь GCC будет считать, что IntAdapter является идентификатором, и будет ожидать, что вы формируете выражение, а не объявление переменной.

Также обратите внимание, что вам не нужно ставить точку с запятой после тела метода!

person Sunlight    schedule 06.11.2008

StructWrapper наследуется от шаблона основного класса (т.е. наименее специализированного), который не определяет IntWrapper, поэтому его нельзя использовать в этом классе. Я не уверен, что создание экземпляра StructWrapper с одним из более специализированных типов позволит ему работать или произойдет сбой при компиляции самого определения класса.

person Greg Rogers    schedule 06.11.2008

Компиляция завершается неудачно, поскольку IntAdapter появляется только в специализированном шаблоне и, следовательно, не виден в точке ссылки.

Непонятно, для чего бы вы его использовали? Пожалуйста, разъясните обстоятельства.

person Denes Tarjan    schedule 06.11.2008
comment
Я думал, что это должно работать, потому что IntAdapter публично наследуется в производном классе. Я не понимаю, почему компиляции StructWrapper терпят неудачу. Я хочу создать адаптер на основе шаблонного параметра и использовать этот адаптер для доступа к компонентам класса. Лучшие предложения? - person ; 06.11.2008