views:

665

answers:

4

I'm trying to create a template class to insulate the users from a data type. I would have preferred to use an adapter class, but the function signatures needed to change requiring a template.

In the code sample below(not the actual project just a simplified version to illustrate the problem), while in the main routine I'm able to use the ob_traits interface. But when I attempt to create the templated StructWrapper which uses the ob_traits as a base class, I get errors and gcc doesn't recognize the IntAdapter class created. This compiles on MSVC 8.0 but fails on gcc 4.1.2 20070626 ( Red hat 4.1.2-14)

So two questions first, do you understand why the compile fails with the errors specified below?

Second, any suggestions on how to implement this concept in a more simple manner?

    #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;
    }
A: 

StructWrapper is inheriting from the primary class template (ie the least specialized), which does not define IntWrapper, so it cannot be used in this class. I'm not sure if instantiating a StructWrapper with one of the more specialized types will allow it to work, or if it fails on compiling the class definition itself.

Greg Rogers
A: 

Similar issue with more concise explanation at: http://stackoverflow.com/questions/11405/template-problem-with-gcc

Dan Pieczynski
A: 

Compile fails because IntAdapter only appears in the specialized template, and therefore it is not visible at the referring point.

Not clear what would you use it for? Please clarify the circumstances.

Denes Tarjan
I thought it should work because IntAdapter is publicly inherited in the derived class. I'm confused why the StructWrapper compilations fail.I want to create an adapter based on the templated parameter, and use that adapter to access the components of the class. Better suggestions?
+2  A: 

dumpOuter fails because IntAdapter needs to be qualified (as in the referenced question). dumpOuterFailsAsWell fails because GCC does parsing of this code,even though it's not complete, and so it needs to know it's a type that you mean:

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

Without typename here, GCC will assume that IntAdapter is an identifier, and will expect you to be forming an expression rather than a variable declaration.

Also note that you do not have to put semicolons after method bodies!

Sunlight