[C++] RTTI en Templates

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Ik ben bezig met een eigen Run Time Type Information implementatie in C++ en heb een probleem met templates en de RTTI declaraties en implementaties. RTTI is geimplementeerd met de volgende klasse en macros die gebruikt worden om een klasse RTTI te geven.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class RTTI
{
public:
    RTTI(const char* name, const RTTI* baseClassType);
    ~RTTI() {}

    const char* GetName () const;
    bool IsExactly (const RTTI& rkType) const;
    bool IsDerived (const RTTI& rkType) const;

protected:
private:
    const char* m_typeName;
    const RTTI* m_baseType;
};

#define DL_DECLARE_RTTI \
public:\
    static const RTTI m_rttiInfo;\
    virtual const RTTI& getType () const { return m_rttiInfo; }

#define DL_IMPLEMENT_BASE_RTTI(CLASSTYPE)\
    const RTTI CLASSTYPE::m_rttiInfo(#CLASSTYPE, 0);

#define DL_IMPLEMENT_RTTI(CLASSTYPE, BASECLASSRTTI)\
    const RTTI CLASSTYPE::m_rttiInfo(#CLASSTYPE, &BASECLASSRTTI::m_rttiInfo);

#define DL_IMPLEMENT_BASE_TEMPLATE_RTTI(CLASSTYPE)\
    template <class T> \
    const RTTI CLASSTYPE<T>::m_rttiInfo(#CLASSTYPE, 0);

#define DL_IMPLEMENT_TEMPLATE_RTTI(CLASSTYPE, BASECLASSRTTI)\
    template <class T> \
    const RTTI CLASSTYPE<T>::m_rttiInfo(#CLASSTYPE, &BASECLASSRTTI::m_rttiInfo);

class Object
{
public:
    Object() {}
    virtual ~Object() {}

    virtual const String toString() const
    {
        return String(m_rttiInfo.GetName());
    }

    DL_DECLARE_RTTI
protected:
};


Het probleem is nu echter dat als je een template hebt die RTTI gebruikt er geen RTTI wordt gegenereerd voor geinstancieerde types van de template. Ik wil niet voor iedere versie een typedef gebruiken om RTTI informatie aan een template te geven.

Weet iemand hier misschien een oplossing voor.

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 19-09 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

Hmm, ik wou hier een verhaaltje typen over dat die members niet gegenereerd worden omdat ze niet gebruikt worden, maar je getType() function is virtual dus ze worden per definitie gegenereerd (omdat de vtable wordt gereferenced in de ctor, en die referenced op zijn beurt weer de getType() functie, etc.). Ik snap het probleem dan ook niet helemaal... Welke compiler gebruik je?

Overigens kun je je macro's wel wat versimpelen door m_rttiInfo een static var te maken binnen de getType() function, die je daar ook meteen kunt initialiseren. Dit maakt de macro die je in de sourcefile moet plaatsen overbodig, en bovendien is er geen verschil meer tussen template en non-template classes.

[ Voor 10% gewijzigd door .oisyn op 16-01-2010 00:07 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Het probleem is dat ik link errors krijg op de instance van de templates hieronder een voorbeeld van een template die ik gerbuik. UniformDescriptorBase is niet meer dan:
C++:
1
2
3
    const String& getName() const { return m_name; }
    const String& getNameLinkedShaderNode() const { return m_linkedShaderNodeName; }
    const UniformDescriptorBase::UniformType getUniformDescriptorType() const { return m_type; }


Boven op de functies in de volgende class.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
template<class T>
class UniformDescriptor : public UniformDescriptorBase
{
public:
    UniformDescriptor(const String& name, const String& linkedShaderNodeName, UniformDescriptorBase::UniformType type, T* data, size_t sizeInBytes, unsigned int nrElements) :
        UniformDescriptorBase(name, linkedShaderNodeName, type),
        m_data(0),
        m_sizeInBytes(sizeInBytes),
        m_nrElements(nrElements)
        {
            copyData(data);
        }
        ~UniformDescriptor(void) 
        {
            cleanup();
        }

        //-----------------------------------------------------------------------------
        //! @brief Cleanup
        //-----------------------------------------------------------------------------
        void cleanup()
        {
            if (m_nrElements == 1)
            {
                DL_SAFE_DELETE(m_data);
            }
            else if (m_nrElements > 1)
            {
                delete [] m_data;
                m_data = 0;
            }
            else
            {
                LOG << "Trying to destroy data that shouldn't exist" << END;
            }
        }
    //Accessors
    const String& getName() const { return m_name; }
    const UniformDescriptorBase::UniformType getUniformDescriptorType() const { return m_type; }
    const T* getData() const { return m_data; }
    T* getWritableData() { return m_data; }
    const size_t getDataSize() const { return m_sizeInBytes; }
    unsigned int getNrElements() const { return m_nrElements; }

    void setName( const String& name ) { m_name = name; }
    void setUniformDescriptorType( const UniformDescriptorBase::UniformType type ) { m_type = type; }
    void setData( T* data ) {  copyData(data); }
    void setByteSize( const size_t size ) { m_sizeInBytes = size; }
    void setNrElements(const unsigned int nrElements) { m_nrElements = nrElements; }

    //Only works for non array types
    size_t calculateByteSize() { m_sizeInBytes = sizeof(T) * m_nrElements; return m_sizeInBytes; }

    DL_DECLARE_RTTI
protected:
    void copyData(T* data)
    {
        if (m_data)
        {
            cleanup();
        }

        if (m_nrElements == 1)
        {
            m_data = new T();
        }
        else if (m_nrElements > 1)
        {
            m_data = new T[m_nrElements];
        }
        else
        {
            LOG << "Trying to create data for " << m_nrElements << " elements for " << m_name << " uniform" << END;
            return;
        }

        for (unsigned int i = 0; i < m_nrElements; ++i)
        {
            m_data[i] = data[i];
        }
    }
private:
    T*           m_data;
    size_t       m_sizeInBytes;
    unsigned int m_nrElements;
};


Het probleem zit erin dat dit naar een .lib wordt gecompiled en dee in een andere project wordt ingeladen. Ik heb voor deze constructie gekozen omdat het me vrij laat om de engine te ontwikkelen los van de game of wat dan ook waarin de engine gebruikt wordt.

Compiler is VS2008 alhoewel ik het ook in 2005 en hoger wil laten compilen als het kan, op het moment is het enkel windows dat wordt onderstuend.

Voor meer code zie dxengine op googlecode, en dan source.

De compile errors zijn deze (en ik weet dat dit forum niet bedoeld is om compile errors op te lossen maar ik zie geen oplossing meer op dit moment):
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>c:\program files (x86)\microsoft visual studio 9.0\vc\include\xutility(618) : error C2734: 'UniformDescriptor<T>::m_rttiInfo' : const object must be initialized if not extern
1>        with
1>        [
1>            T=float
1>        ]
1>        e:\sdk\dx_engine\src\graphics\uniformdescriptor.h(98) : while compiling class template static data member 'const RTTI UniformDescriptor<T>::m_rttiInfo'
1>        with
1>        [
1>            T=float
1>        ]
1>        e:\sdk\dx_engine\src\graphics\uniforminstance.cpp(32) : see reference to class template instantiation 'UniformDescriptor<T>' being compiled
1>        with
1>        [
1>            T=float
1>        ]


Andere compile errors die ik had waren dat het project dat de lib gebruikt geen m_rttiinfo kon genereren voor de template instance float, vector2 enz. van bovenstaande classe.

Ik snap je sugestie maar ik wil nog functies aan object toevoegen om te kijken of een class een bepaal d type is of een derived. En daarvoor wil ik het liefst geen strcmp voor gebruiken maar gebruikmaken van het fiet dat m_rttiInfo static is zodat ik alleen maar adressen hoef te vergelijken.

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


Acties:
  • 0 Henk 'm!

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

Ik zie je nergens
code:
1
DL_IMPLEMENT_TEMPLATE_RTTI(UniformDescriptor , UniformDescriptorBase)

gebruiken.

Mijn vermoeden is dat de compiler daarover valt.

ASSUME makes an ASS out of U and ME


Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Ik heb ook niet mijn volledige code gepast DL_IMPLEMENT_TEMPLATE_RTTI wordt er ondergebruikt sorry dat ik dat niet poste gisteren maar het was nogal laat.

Als je de compile error ziet zie je dat dat geen link error is, wat het wel zou zijn als ik DL_IMPLEMENT_TEMPLATE_RTTI vergeten was.

Ik denk dat ik het opgelost heb ik denk dat de compiler over een andere link error over de kop ging en andere link errors begon te melden. :s

edit:

Het werkelijke probleem was dat de DL_IMPLEMENT_TEMPLATE_RTTI in een cpp stond en niet in de header, stomme fout :(

[ Voor 13% gewijzigd door NC83 op 16-01-2010 14:58 ]

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 19-09 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

NC83 schreef op zaterdag 16 januari 2010 @ 04:51:
Ik snap je sugestie maar ik wil nog functies aan object toevoegen om te kijken of een class een bepaal d type is of een derived. En daarvoor wil ik het liefst geen strcmp voor gebruiken maar gebruikmaken van het fiet dat m_rttiInfo static is zodat ik alleen maar adressen hoef te vergelijken.
Als je getType() zo implementeert:
C++:
1
2
3
4
5
virtual const RTTI& getType () const
{
    static const RTTI rttiInfo(#CLASSTYPE, 0); 
    return rttiInfo;
}

Dan kun je gewoon adressen vergelijken. Het nadeel is wel dat het RTTI object pas wordt geconstruct zodra je getType() voor de eerste keer aanroept.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1