[C++] probleem met templates base-class initializers.

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • TumbleCow
  • Registratie: Januari 2000
  • Laatst online: 08-09 12:24

TumbleCow

Waarschijnlijkheids elastiekje

Topicstarter
Ik probeer Bayes++ te gebruiken om een tracker te bouwen, en ik blijf tegen het volgende probleem aanlopen:

Het lijkt er op dat een zekere base-class initializer voor een base-class zonder default constructor in een template class niet correct meegenomen wordt.

De 'Track' klasse kan via een template class een willekeurige base-class hebben.

Track.h
C++:
1
2
3
4
5
6
template <class SCHEME>
class Track : public SCHEME
{
    Track(int stateSize) :  SCHEME(stateSize, stateSize)
     { }
};


Hiermee wordt de constructor van SCHEME, in dit geval UD_scheme, aangeroepen:

UDFlt.hpp
C++:
1
2
3
4
class UD_scheme : public Linrz_kalman_filter
{
   UD_scheme (std::size_t x_size, std::size_t q_maxsize, std::size_t z_initialsize = 0);
};


UDFlt.cpp
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
UD_scheme::
UD_scheme (std::size_t x_size, std::size_t q_maxsize, std::size_t z_initialsize) :
                Kalman_state_filter(x_size),  // <-----
                q_max(q_maxsize),
                UD(x_size,x_size+q_max),
                s(Empty), Sd(Empty),
                d(x_size+q_max), dv(x_size+q_max), v(x_size+q_max),
                a(x_size), b(x_size),
                h1(x_size), w(x_size),
                znorm(Empty),
                zpdecol(Empty),
                Gz(Empty),
                GIHx(Empty)
{
}


De Kalman_state_filter is een virtual superklasse van de Linrz_kalman_filter superklasse.
Deze klasse heeft geen default constructor, en de base-class initializer Kalman_state_filter(x_size) lijkt niet goed gecompileerd te worden:
code:
1
2
3
Track.h:38: error: no matching function for call to &#8216;Bayesian_filter::Kalman_state_filter::Kalman_state_filter()&#8217;
/usr/local/include/Bayes++/bayesFlt.hpp:493: note: candidates are: Bayesian_filter::Kalman_state_filter::Kalman_state_filter(size_t)
/usr/local/include/Bayes++/bayesFlt.hpp:489: note:                 Bayesian_filter::Kalman_state_filter::Kalman_state_filter(const Bayesian_filter::Kalman_state_filter&)


Het toevoegen van deze initializer aan mijn eigen 'Track' klasse lost het probleem op:
C++:
1
2
3
4
5
6
template <class SCHEME>
class Track : public SCHEME
{
    Track(int stateSize) :  SCHEME(stateSize, stateSize), Kalman_state_filter(stateSize)
    { }
};


Iemand enig idee waarom de initializer in UDFlt.cpp niet goed opgepakt wordt?
Alvast ontzettend bedankt!

[ Voor 3% gewijzigd door TumbleCow op 28-01-2009 15:47 ]


Acties:
  • 0 Henk 'm!

  • TumbleCow
  • Registratie: Januari 2000
  • Laatst online: 08-09 12:24

TumbleCow

Waarschijnlijkheids elastiekje

Topicstarter
Hierbij moet ik zeggen dat na het toevoegen van de Kalman_state_filter initializer bij de constructor van de Track-klasse, hetzelfde probleem zich een niveau hoger voor doet:

C++:
1
2
3
4
5
6
7
8
template <class SCHEME>
class MotionModelTrack : public Track<SCHEME>
{
        MotionModelTrack() : Track<SCHEME>(4)//, Kalman_state_filter(4)
        {
                init();
        }
};


code:
1
2
3
Tracker.h:41: error: no matching function for call to &#8216;Bayesian_filter::Kalman_state_filter::Kalman_state_filter()&#8217;
/usr/local/include/Bayes++/bayesFlt.hpp:493: note: candidates are: Bayesian_filter::Kalman_state_filter::Kalman_state_filter(size_t)
/usr/local/include/Bayes++/bayesFlt.hpp:489: note:                 Bayesian_filter::Kalman_state_filter::Kalman_state_filter(const Bayesian_filter::Kalman_state_filter&)


Mijn initiele intuitie was dat dit probleem veroorzaakt werd doordat de compiler de base-class initializer in UDFlt.cpp niet kon vinden, omdat het de .h file is die geinclude wordt.
De base-class initializer staat nu echter netjes in de bovengenoemde Track.h file.

Ik ben wanhopig en reddeloos verloren. ;)
Iemand enig idee?

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-09 16:37

.oisyn

Moderator Devschuur®

Demotivational Speaker

Iemand enig idee?
Ja, je hebt pech :). Voor virtual base classes is de most derived class altijd verantwoordelijk voor de construction.

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!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Dit:

UD_scheme::
UD_scheme (std::size_t x_size, std::size_t q_maxsize, std::size_t z_initialsize) :
Kalman_state_filter(x_size), // <-----

is toch sowieso niet geldig? Of vergis ik me? Het moet toch een directe base class zijn of een member?

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-09 16:37

.oisyn

Moderator Devschuur®

Demotivational Speaker

Lees nu mijn post nog een keer ;)

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!

  • TumbleCow
  • Registratie: Januari 2000
  • Laatst online: 08-09 12:24

TumbleCow

Waarschijnlijkheids elastiekje

Topicstarter
.oisyn schreef op woensdag 28 januari 2009 @ 16:56:
[...]

Ja, je hebt pech :). Voor virtual base classes is de most derived class altijd verantwoordelijk voor de construction.
Wauw. Dat was inderdaad net even de factlet die ik miste. Ontzettend bedankt!

Om het ook even voor toekomstige generaties uit te leggen:
Zoijar schreef op woensdag 28 januari 2009 @ 17:18:
Dit:

UD_scheme::
UD_scheme (std::size_t x_size, std::size_t q_maxsize, std::size_t z_initialsize) :
Kalman_state_filter(x_size), // <-----

is toch sowieso niet geldig? Of vergis ik me? Het moet toch een directe base class zijn of een member?
Zoijar, je hebt bij niet-virtual base-classes volledig gelijk. Dan heb je 'gewoon' deze situatie:
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
#include <iostream>

class WantsInitializer
{
public:
        WantsInitializer(int a)
        {
                std::cout << a << std::endl;
        }
};

class BaseClass : public /*virtual*/ WantsInitializer
{
public:
        BaseClass() : WantsInitializer(1)
        {
        }

        BaseClass(int a) : WantsInitializer(a)
        {
        }
};

class SubClass : public BaseClass
{
public:
        SubClass() : BaseClass(1) /*,WantsInitializer(2)*/
        {
        }
};

int main()
{
        //WantsInitializer c; // fails 

        SubClass s;

        return 0;
}


Kijk wat er gebeurt als ik WantsInitialiser een virtual base-class maak van BaseClass.
Nu *moet* ik in SubClass WantsInitializer initializeren, wat dus geen directe base-class is.
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
#include <iostream>

class WantsInitializer
{
public:
        WantsInitializer(int a)
        {
                std::cout << a << std::endl;
        }
};

class BaseClass : public virtual WantsInitializer
{
public:
        BaseClass() : WantsInitializer(1)
        {
        }

        BaseClass(int a) : WantsInitializer(a)
        {
        }
};

class SubClass : public BaseClass
{
public:
        SubClass() : /*BaseClass(1),*/ WantsInitializer(2)
        {
        }
};

int main()
{
        //WantsInitializer c; // fails 

        SubClass s;

        return 0;
}


Nu is de output van het programmatje dan ook '2'. Het aanroepen van WantsInitializer door BaseClass met waarde 1 vindt nooit plaats.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-09 16:37

.oisyn

Moderator Devschuur®

Demotivational Speaker

De reden hiervoor is overigens vrij simpel. In jouw usecase treedt het probleem wellicht niet op, maar als je de bekende diamant inheritance structuur gebruikt is het ambigu wie nou verantwoordelijk is voor de construction. Voorbeeld:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct A
{
    A(int) { }
};

struct B : virtual A
{
    B() : A(1) { }
};

struct C : virtual A
{
    C() : A(2) { }
};

struct D : B, C
{
    D() { }
};

Het is voor D niet duidelijk wie A nou moet constructen. B kan het doen, die construct A met een 1. Maar C kan het ook doen, die doet het met een 2. En dus moet D het maar bepalen.

Nou zou je kunnen denken dat het dan opgelost is als D de keuze maakt, waardoor het voor een E die D extend niet nog een keer hoeft te gebeuren. Maar bedenk al dat dit in feite precies dezelfde situatie is als bij B en C. Ook daar was het nog niet ambigu. Maar omdat er van B en C werd overgeërft, waarbij er ineens ook een ander pad naar A mogelijk werd, ging dat niet meer op. Vandaar de regel dat de most derived class er altijd voor moet zorgen.

Helaas is dat met templates waarbij de baseclass een dependent type is een beetje problematisch. Je weet nooit wat voor verantwoordelijkheden de template class er ineens bij krijgt. Wat dat betreft is het jammer dat je een virtual base class niet non-virtual kan maken in een derived class.

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!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

wHiTeRaZoR schreef op woensdag 28 januari 2009 @ 18:46:
Zoijar, je hebt bij niet-virtual base-classes volledig gelijk. Dan heb je 'gewoon' deze situatie:
Ahhh, ok, ik had even het virtual gedeelte gemist... ik ben niet echt wakker vandaag geloof ik :P
Pagina: 1