Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Phil_GDM

Alter Hase

  • »Phil_GDM« ist der Autor dieses Themas

Beiträge: 443

Wohnort: Graz

Beruf: Student-Softwareentwicklung u. Wissensmanagement

  • Private Nachricht senden

1

16.02.2009, 20:03

[Solved] C++ Templates Methode per Policy aufrufen

Hallo

Ich hab gerade ein design-problem mit templates.

Derzeit arbeite ich an generischen Grafik-Datenstrukturen. Z.B. bin ich gerade dabei einen Octree zu implementieren:

C-/C++-Quelltext

1
template<typename TNumeric, typename TNodeData> class Octree ...;


Das Problem ist jetzt, damit ein Objekt vom Typ TNodeData eingefügt werden kann, muss ich seine AABB kennen, ergo muss eine Methode von TNodeData aufgerufen werden, die die AABB zurückliefert.

Also habe ich eine Policy-Klasse erstellt, die genau das machen soll:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  template <typename TNumeric, typename TNodeData>
  class OctreeAABBPolicy
  {
  public:
        static AxisAlignedBB<TNumeric> getAABB(TNodeData const& data)
    {
      return data.getAABB();
    }
  };


  template <typename TNumeric, typename TNodeData>
  class OctreeAABBPolicy<TNumeric, TNodeData*>
  {
  public:
    static AxisAlignedBB<TNumeric> getAABB(TNodeData const* data)
    {
      return data->getAABB();
    }
  };


Stellt TNodeData keine Methode getAABB zur Verfügung spezialisiert man die Policy einfach für seine Datenstruktur und gut ist es.

Nun hat sich aber die Situation ergeben, dass die Policy nicht immer für den Datentyp spezialisiert werden kann:

C-/C++-Quelltext

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
    template <
        typename TNumeric,
        typename THalfEdgeStructure
    >
    class IntersectionCutter
    {

        typedef typename THalfEdgeStructure::FaceType*                                          FaceType;
        typedef Octree<TNumeric, typename THalfEdgeStructure::FaceType*>        SpeedUpStructureType;
        typedef typename SpeedUpStructureType::AABBType                                         AABBType;


   //Speizialisierung müsste hier sein, da erst hier TNumeric u. FaceType bekannt sind

   //template<>

   //class OctreeAABBPolicy<TNumeric, FaceType> {.... return aabbFromFace(data); };

   //das geht aber nicht, da man in diesem Skope keine Spezialisierung machen darf

    protected:

            AABBType aabb                                                                                           = aabbFromFace(*iter);
            dest.addItemAABB(*iter, aabb);

        }


        AABBType aabbFromFace(typename THalfEdgeStructure::FaceType const* face)
        {
            typedef THalfEdgeStructure::FaceType::HalfEdgeContainer         EdgeContainer;
            EdgeContainer edges = face->getHalfEdges();

            EdgeContainer::const_iterator iter;
            AABBType resultBox;
            for(iter = edges.begin(); iter != edges.end(); ++iter)
            {
                resultBox.expand((*iter)->end()->getCoordinate());
                resultBox.expand((*iter)->start()->getCoordinate());
            }

            return resultBox;
        }
        
    };


Meine nächste Idee war, die Policy als Template-Argument im Octree zu spezifizieren

C-/C++-Quelltext

1
2
3
4
5
class Octree
<
   typename TNumeric, 
   typename TNodeData, 
   template<typename, typename> class TAABBPolicy = OctreeAABBPolicy<TNumeric, TNodeData>


Leider geht so etwas ja auch nicht (da nicht C++ konform) und ich will auf keinen Fall, dass der User immer die Policy angeben muss, selbst wenn seine Datenstruktur getAABB zur Verfügung stellt. Irgendwie fällt mir einfach keine saubere Lösung für mein Problem ein.

Meine Frage ist nun: Hat jemand von euch eine Idee, wie man dieses Problem lösen könnte (sofern jemand von euch verstanden hat, was ich will ;) )?

mfg Philipp

2

16.02.2009, 20:12

zu deiner zweiten Idee: so müsste es gehen:

C-/C++-Quelltext

1
2
3
4
5
6
class Octree
<
   typename TNumeric,
   typename TNodeData,
   typename TAABBPolicy = OctreeAABBPolicy<TNumeric, TNodeData> 
>

eine class ist ein typename, und eine ausreichend spezialisierte template-class wird wie eine ganz normale class behandelt - die STL machts z.B. bei Alokatoren auch so ;)

Phil_GDM

Alter Hase

  • »Phil_GDM« ist der Autor dieses Themas

Beiträge: 443

Wohnort: Graz

Beruf: Student-Softwareentwicklung u. Wissensmanagement

  • Private Nachricht senden

3

16.02.2009, 20:22

Nein das geht leider nicht (c2977).

C++ Templates the complete guide sagt dazu:

A template template argument must be a class template with parameters that exactly match the paramters of the template template parameter it substitutes.

This makes following example invalid:

C-/C++-Quelltext

1
2
3
4
namespace std{
  template <typename T, typename Allocator = allocator<T> >
  class list;
}


EDIT: Hab gerade gesehen dass in <list> wirklich folgendes Konstrukt ist

C-/C++-Quelltext

1
2
3
template<class _Ty,
    class _Ax = allocator<_Ty> >
    class list ...


wenn ich das aber mache:

C-/C++-Quelltext

1
2
3
4
5
6
  template <
    typename TNumeric,
    typename TNodeData,
        typename TAABBPolicy = OctreeAABBPolicy<TNumeric, TNodeData> 
    >
  class Octree...

bekomme ich einen compiler-fehler :?

mfg Philipp

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

4

16.02.2009, 20:32

C-/C++-Quelltext

1
2
3
4
5
class Octree 
< 
   typename TNumeric, 
   typename TNodeData, 
   template<typename, typename> class TAABBPolicy = OctreeAABBPolicy<TNumeric, TNodeData> 


Du setzt hier eine Instanz eines template als default Parameter!?

sollte imo eher so aussehen:

C-/C++-Quelltext

1
2
3
4
5
class Octree 
< 
   typename TNumeric, 
   typename TNodeData, 
   template<typename, typename> class TAABBPolicy = OctreeAABBPolicy

5

16.02.2009, 20:37

@Phil_GDM: das kann eigentlich nicht sein, was für die STL gilt muss auch für dich gelten ;)

Phil_GDM

Alter Hase

  • »Phil_GDM« ist der Autor dieses Themas

Beiträge: 443

Wohnort: Graz

Beruf: Student-Softwareentwicklung u. Wissensmanagement

  • Private Nachricht senden

6

16.02.2009, 20:46

Also ich habe jetzt alle hier genannten Möglichkeiten ausprobiert, und immer erhalte ich folgenden Fehler:

error C2977: too many template arguments

@PCShadow: Ist mir schon klar, deswegen auch der Confused-Smiley. Aber ich kanns nicht ändern, ich erhalte solange das 3-te Template Argument da ist, immer den obigen Compiler-Fehler.

mfg Philipp

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

7

16.02.2009, 20:46

Was ist mit:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
template< typename T >
class OctreeAABBPolicy
{
    typedef typename T::TNumeric TNumeric;

public:
    static AxisAlignedBB<TNumeric> getAABB(T const& data)
    {
      return data.getAABB();
    }
};

Phil_GDM

Alter Hase

  • »Phil_GDM« ist der Autor dieses Themas

Beiträge: 443

Wohnort: Graz

Beruf: Student-Softwareentwicklung u. Wissensmanagement

  • Private Nachricht senden

8

16.02.2009, 20:53

Zitat von »"David_pb"«

Was ist mit:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
template< typename T >
class OctreeAABBPolicy
{
    typedef typename T::TNumeric TNumeric;

public:
    static AxisAlignedBB<TNumeric> getAABB(T const& data)
    {
      return data.getAABB();
    }
};


Irgendwie versteh ich nicht, was das mit meinem Problem zu tun hat.

mfg Philipp

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

9

16.02.2009, 20:54

Hm... Mist, denkfehler! :) Aber:

C-/C++-Quelltext

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
template< typename T >
class AxisAlignedBB
{
};

template< typename TNumeric, typename TNodeData >
class OctreeAABBPolicy
{
public:
    static AxisAlignedBB<TNumeric> getAABB(TNodeData const& data)
    {
      return data.getAABB();
    }
};

template <
    typename TNumeric,
    typename TNodeData,
    typename TAABBPolicy = OctreeAABBPolicy<TNumeric, TNodeData> > 
class Octree
{
};

template <
    typename T,
    typename THalfEdgeStructure
>
class IntersectionCutter
{ 
public:
    typedef T TNumeric;
};


Compiliert fehlerfrei.

Allerdings würde ich den Umweg garnicht machen sondern einfach erwarten das TNodeData eine entsprechende Methode anbietet... Is ja nich zu viel verlangt! ;)

10

16.02.2009, 21:02

Zitat von »"David_pb"«

Hm... Mist, denkfehler! :) Aber:

C-/C++-Quelltext

1
2
3
4
5
6
7
template <
    typename TNumeric,
    typename TNodeData,
    typename TAABBPolicy = OctreeAABBPolicy<TNumeric, TNodeData> > 
class Octree
{
};


Compiliert fehlerfrei.

bei dir vllt, aber bei ihm macht sowas offensichtlich probleme - wir sollten mal compiler vergleichen.
mit mingw compiliert

C-/C++-Quelltext

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
#include <iostream>

using namespace std;

template <typename T> class Bar
{
    public:
    T data;
};

template <typename A, typename B = Bar<A> > class Foo
{
    public:
    A x;
    B y;
};



int main()
{
    Foo<char> F;
    cin >> F.x >> F.y.data;
    cout << F.x << F.y.data;
    cin.get();
    return 0;
}

fehlerfrei. man muss allerdings beachten, das zwischen den beiden '>' min. ein whitespace liegen muss, da sie sonst als ein token interpretiert werden

//EDIT: ja, aber es stört mich trotzdem, dass sowas bei ihm nicht zu compilieren scheint - ein problem zu umgehen, löst es imo nicht ;)

Werbeanzeige