Forum: PC-Programmierung c++ Klassen Deklaration/Definition


von Rasputin (Gast)


Lesenswert?

Hilfe Forum,

Wie mache ich bei folgendem Code die Deklaration/Definition richtig?
1
#include <memory>
2
#include <set>
3
4
struct A;
5
struct B;
6
struct less;
7
8
struct A {
9
  typedef std::shared_ptr<A> ptr_t;
10
  typedef std::set<ptr_t, less> set_t;
11
12
  int value;
13
14
  A(int _value) : value(_value) {
15
  }
16
};
17
18
struct B {
19
  typedef std::shared_ptr<B> ptr_t;
20
  typedef std::set<ptr_t, less> set_t;
21
22
  int num;
23
24
  A::set_t data;
25
26
  B(int _num) : num(_num) {
27
  }
28
};
29
30
struct less {
31
  bool operator()(const A::ptr_t &lh, const A::ptr_t &rh) {
32
    return lh->value < rh->value;
33
  }
34
35
  bool operator()(const B::ptr_t &lh, const B::ptr_t &rh) {
36
    return lh->num < rh->num;
37
  }
38
};
39
40
struct C {
41
  B::set_t data;
42
};
43
44
45
int main() {
46
  A::ptr_t a1(new A(1));
47
  A::ptr_t a2(new A(2));
48
49
  B::ptr_t b(new(1));
50
51
  b->data.insert(a1);
52
  b->data.insert(a2);
53
54
  C c;
55
56
  c.data.insert(b);
57
58
}

Ich krieg' gleich die Kriese und bin dankbar für jede Hilfe! :/

von Sebastian V. (sebi_s)


Lesenswert?

Vor der Definition deiner Klassen A und B muss die less Klasse bekannt 
sein. Das kannst du z.B. durch folgende Definition der Klasse erreichen:
1
struct less {
2
  bool operator()(const std::shared_ptr<A> &lh, const std::shared_ptr<A> &rh);
3
  bool operator()(const std::shared_ptr<B> &lh, const std::shared_ptr<B> &rh);
4
};

Die Definition der Funktionen kann dann erst folgen wenn die Klassen A 
und B auch definiert wurden. Eine Möglichkeit direkt die typedefs in 
deiner Klasse zu benutzen fällt mir jetzt nicht ein.

von Wilhelm M. (wimalopaan)


Lesenswert?

Mit einem template, da der code strukturell identisch ist, bzw. nur vom 
DT abhängig ist. Ausserdem erfolgt die Instanziierung eines Templates 
"lazy", also erst da, wo sie gebraucht wird.
1
#include <memory>
2
#include <set>
3
4
struct A;
5
struct B;
6
//struct less;
7
8
template<typename T>
9
struct less {
10
  bool operator()(const typename T::ptr_t &lh, const typename T::ptr_t &rh) {
11
    return lh->value < rh->value;
12
  }
13
};
14
15
struct A {
16
  typedef std::shared_ptr<A> ptr_t;
17
  typedef std::set<ptr_t, less<A>> set_t;
18
19
  int value;
20
21
  A(int _value) : value(_value) {
22
  }
23
};
24
25
struct B {
26
  typedef std::shared_ptr<B> ptr_t;
27
  typedef std::set<ptr_t, less<B>> set_t;
28
29
  int num;
30
  int value;
31
32
  A::set_t data;
33
34
  B(int _num) : num(_num) {
35
  }
36
};
37
38
39
struct C {
40
  B::set_t data;
41
};
42
43
44
int main() {
45
  A::ptr_t a1(new A(1));
46
  A::ptr_t a2(new A(2));
47
48
  B::ptr_t b(new B(1));
49
50
  b->data.insert(a1);
51
  b->data.insert(a2);
52
53
  C c;
54
55
  c.data.insert(b);
56
57
}

Wobei ich mal eben Dein Datenelement umbenannt habe in B. Falls dass 
nicht gewüncht ist, müsstest Du das template less für B spezialisieren 
...

: Bearbeitet durch User
von nicht“Gast“ (Gast)


Lesenswert?

Moin,

Ehrlich.nach das so nicht. Schon bei den kleinen Schnipsel Code ist es 
schon nicht mehr intuitiv durchzusehen was da passieren soll. Lass den 
mal ein wenig größer werden und ein halbes Jahr vergehen. Dann sieht 
keiner mehr durch. Sich du nicht.

von Wilhelm M. (wimalopaan)


Lesenswert?

Warum ist der "normale" Weg für Dich nicht anwendbar?
1
struct A {
2
  typedef std::shared_ptr<A> ptr_t;
3
  typedef std::set<ptr_t> set_t;
4
5
  int value;
6
7
  A(int _value) : value(_value) {
8
  }
9
};
10
11
bool operator<(const A& lhs, const A& rhs) {
12
    return lhs.value < rhs.value;
13
}

von Sebastian V. (sebi_s)


Lesenswert?

Wilhelm M. schrieb:
> Warum ist der "normale" Weg für Dich nicht anwendbar? [...]

So würde das set doch nur die shared_ptr vergleichen, aber nicht die 
Werte. Aber für das Problem würde ich mir dann ein ptr_less Functor 
bauen der Pointer vergleicht indem er sie dereferenziert und die Werte 
vergleicht.

von Wilhelm M. (wimalopaan)


Lesenswert?

Jo klar, meinte auch das:
1
bool operator<(const std::shared_ptr<A>& lhs, const std::shared_ptr<A>& rhs) {
2
    return lhs->value < rhs->value;
3
}

von Rasputin (Gast)


Lesenswert?

Danke sehr für die zahlreiche Beteiligung!

Wilhelm M. schrieb:
> Warum ist der "normale" Weg für Dich nicht anwendbar?

Funktioniert leider so nicht (auch dein 2ter Vorschlag). Ich schätze, 
weil für std::shared_ptr<T> bereits alle Vergleichsoperatoren definiert 
sind:
http://de.cppreference.com/w/cpp/memory/shared_ptr/operator_cmp

Wilhelm M. schrieb:
> Mit einem template, da der code strukturell identisch ist, bzw. nur vom
> DT abhängig ist.

Ist er leider nicht. Ich habe absichtlich A::value und B::num genannt, 
denn im eigentlichen Code heissen die auch nicht gleich. Ich kann diese 
Variable nicht umbenennen (bzw. ich will nicht, weil dadurch der Sinn 
nicht mehr ersichtlich wäre).

Sebastian V. schrieb:
> Die Definition der Funktionen kann dann erst folgen wenn die Klassen A
> und B auch definiert wurden. Eine Möglichkeit direkt die typedefs in
> deiner Klasse zu benutzen fällt mir jetzt nicht ein.

Ok, trotzdem Danke.

nicht“Gast“ schrieb:
> Moin,
>
> Ehrlich.nach das so nicht. Schon bei den kleinen Schnipsel Code ist es
> schon nicht mehr intuitiv durchzusehen was da passieren soll. Lass den
> mal ein wenig größer werden und ein halbes Jahr vergehen. Dann sieht
> keiner mehr durch. Sich du nicht.

Auf was beziehst du dich?

von Wilhelm M. (wimalopaan)


Lesenswert?

Wie wärs damit?
1
#include <memory>
2
#include <set>
3
#include <functional>
4
5
struct A {
6
    int value;
7
    A(int _value) : value(_value) {}
8
};
9
10
namespace std {
11
template<>
12
struct less<std::shared_ptr<A>> {
13
      bool operator()(const std::shared_ptr<A> &lh, const std::shared_ptr<A> &rh) {
14
          std::cout << __PRETTY_FUNCTION__ << std::endl;
15
          return lh->value < rh->value;
16
      }
17
}; 
18
}
19
20
struct B {
21
    typedef std::shared_ptr<A> ptr_t;
22
    typedef std::set<ptr_t, std::less<std::shared_ptr<A>>> set_t;
23
    
24
    int num;
25
26
    set_t data;
27
    
28
    B(int _num) : num(_num) {}
29
};
30
31
namespace std {
32
template<>
33
struct less<std::shared_ptr<B>> {
34
      bool operator()(const std::shared_ptr<B> &lh, const std::shared_ptr<B> &rh) {
35
          std::cout << __PRETTY_FUNCTION__ << std::endl;
36
          return lh->num < rh->num;
37
      }
38
}; 
39
}
40
41
struct C {
42
    typedef std::shared_ptr<B> ptr_t;
43
    typedef std::set<ptr_t, std::less<std::shared_ptr<B>>> set_t;
44
    set_t data;
45
};
46
47
48
int main() {
49
  B::ptr_t a1(new A(1));
50
  B::ptr_t a2(new A(2));
51
52
  C::ptr_t b(new B(1));
53
54
  b->data.insert(a1);
55
  b->data.insert(a2);
56
57
  C c;
58
59
  c.data.insert(b);
60
61
}

von Wilhelm M. (wimalopaan)


Lesenswert?

Du kannst auch für std::set den Comparator-Typ-Parameter weglassen fällt 
mir grad auf. Denn die vollständige Spezialisierung hat ja gegenüber dem 
allgemeiner Template Vorrang:
1
struct B {
2
    typedef std::shared_ptr<A> ptr_t;
3
    typedef std::set<ptr_t> set_t;
4
    
5
    int num;
6
7
    set_t data;
8
    
9
    B(int _num) : num(_num) {}
10
};

von Rasputin (Gast)


Lesenswert?

Ich hatte noch eine Idee. Und funktioniert sogar ;) Wirkt auf mich 
relativ sauber.
1
#include <memory>
2
#include <set>
3
4
struct A;
5
struct B;
6
7
struct shared_ptr_less {
8
  template <typename T>
9
  bool operator()(const std::shared_ptr<T> &lh, const std::shared_ptr<T> &rh) {
10
    return (*lh) < (*rh);
11
  }
12
};
13
14
struct A {
15
  typedef std::shared_ptr<A> ptr_t;
16
  typedef std::set<ptr_t, shared_ptr_less> set_t;
17
18
  const int value;
19
20
  A(int _value) : value(_value) {
21
  }
22
};
23
24
struct B {
25
  typedef std::shared_ptr<B> ptr_t;
26
  typedef std::set<ptr_t, shared_ptr_less> set_t;
27
28
  const int num;
29
30
  A::set_t data;
31
32
  B(int _num) : num(_num) {
33
  }
34
};
35
36
inline bool operator<(const A &lh, const A &rh) {
37
  return lh.value < rh.value;
38
}
39
40
inline bool operator<(const B &lh, const B &rh) {
41
  return lh.num < rh.num;
42
}
43
44
struct C {
45
  B::set_t data;
46
};
47
48
int main() {
49
  A::ptr_t a1(new A(10));
50
  A::ptr_t a2(new A(2));
51
  A::ptr_t a3(new A(1024));
52
  A::ptr_t a4(new A(128));
53
54
  B::ptr_t b(new B(1));
55
56
  b->data.insert(a1);
57
  b->data.insert(a2);
58
  b->data.insert(a3);
59
  b->data.insert(a4);
60
61
  for (auto it = b->data.begin(); it != b->data.end(); it++) {
62
    printf("%i\n", (*it)->value);
63
  }
64
65
  C c;
66
67
  c.data.insert(b);
68
}

P.S.: oben habe ich noch const vor int vergessen! Das ist natürlich sehr 
wichtig!

von Wilhelm M. (wimalopaan)


Lesenswert?

Ja, geht auch, wenn Du auch möchtest, dass die DT A bzw. B generell 
anordnenbar sein sollen. Aber das wird wohl so sein.

Das "normale" Vorgehen, ist allerdings std::less zu spezialisieren - in 
dem Sinne, dass man das gewissermaßen erwartet ... Das kannst Du ja aber 
auch mit Deinem Ansatz kombinieren.

von Rasputin (Gast)


Lesenswert?

Wilhelm M. schrieb:
> namespace std {
> template<>
> struct less<std::shared_ptr<A>> {
>       bool operator()(const std::shared_ptr<A> &lh, const
> std::shared_ptr<A> &rh) {
>           std::cout << _PRETTY_FUNCTION_ << std::endl;
>           return lh->value < rh->value;
>       }
> };
> }

Bist du sicher? Ich bekomme:
error: redefinition of 'struct std::less<std::shared_ptr<A> >'

von Wilhelm M. (wimalopaan)


Lesenswert?

Ja.
Poste bitte Deinen gesamten Code.

von Rasputin (Gast)


Lesenswert?

Fehlalarm. Beim 2ten Mal gings. Muss wohl irgendwas doppel kopiert 
haben.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.