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

Nimelrian

Alter Hase

  • »Nimelrian« ist der Autor dieses Themas

Beiträge: 1 216

Beruf: Softwareentwickler (aktuell Web/Node); Freiberuflicher Google Proxy

  • Private Nachricht senden

1

11.04.2014, 16:20

[C++] Templates

Templates... Funktionieren sie, liebt man sie, tun sie es nicht... (Ich gehöre aktuell zur zweiten Gruppe)

Das Problem stammt aus meinem aktuellen Projekt, (siehe hier), und dem Versuch, eXpl0it3rs Vorschlag umzusetzen:

Zitat

srand wird per C++14 als deprecated markiert sein, also tust du gut jetzt schon auf den <random> header umzusteigen.

Nach einigem hin und her bin ich dann bei der Aufgabe gelandet, einen RNG mit Templates zu basteln.

Aufgrund der Eigenheiten des random-Headers gibt es allerdings 2 verschiedene Klassen, um Verteilungen über Integer und Gleitkommazahlen zu erstellen. (std::uniform_int_distribution und std::uniform_real_distribution)

Aktuell nutze ich nur int und float Zufallszahlen, eventuell kann ich aber später auch mal long/double/foo brauchen.
Dementsprechend muss ich das ganze spezifizieren.

Hier die Dateien, die ich am Anfang hatte:
hpp:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#pragma once
#include <random>

template <typename T>
class RNG {
public:
    RNG(T type) {};
    void setSeed(unsigned long seed) { rng.seed(seed) };
    T nextRandom(T& min, T& max);
    float nextRandom(const float min, const float max);
private:
    std::default_random_engine rng;
    T min;
    T max;
};

cpp:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
#include "RNG.hpp"
template <typename T>
T RNG::nextRandom(const T& min, const T& max) {
    std::uniform_int_distribution<T> dist(min, max);
    return dist(rng);
}

template <>
float RNG::nextRandom(const float min, const float max) {
    std::uniform_real_distribution<float> dist(min, max);
    return dist(rng);
}


Intellisense streicht mir allerdings float RNG::nextRandom(const float min, const float max) an (bei RNG)

Zitat

Error: Die Argumentliste für "Klassenvorlage "RNG"" fehlt


Im Chat wurde mir dann mitgeteilt, dass das Aufteilen von templates auf hpp und cpp nicht so einfach wäre und ich das ganze auf 3 Dateien (hpp, cpp, inl) aufteilen solle. Diese sehen nun so aus:

hpp:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#pragma once
#include <random>

template <typename T>
class RNG {
public:
    RNG(T type) {};
    void setSeed(unsigned long seed) { rng.seed(seed) };
    T nextRandom(T& min, T& max);
    float nextRandom(const float min, const float max);
private:
    std::default_random_engine rng;
    T min;
    T max;
};

#include "RNG.inl"

inl:

C-/C++-Quelltext

1
2
3
4
5
template <typename T>
T RNG::nextRandom(const T& min, const T& max) {
    std::uniform_int_distribution<T> dist(min, max);
    return dist(rng);
}

cpp:

C-/C++-Quelltext

1
2
3
4
5
6
7
#include "RNG.hpp"

template <>
float RNG::nextRandom(const float min, const float max) {
    std::uniform_real_distribution<float> dist(min, max);
    return dist(rng);
}


Wenn ich nun versuche, die cpp zu kompilieren, bekomme ich folgende Fehler:

Zitat

1>------ Erstellen gestartet: Projekt: Lunar Defense, Konfiguration: Debug Win32 ------
1> RNG.cpp
1>c:\users\sebastian\documents\visual studio 2013\projects\lunar defense\lunar defense\rng.inl(2): error C2955: 'RNG' : Für die Verwendung von Klasse template ist eine template-Argumentliste erforderlich
1> c:\users\sebastian\documents\visual studio 2013\projects\lunar defense\lunar defense\rng.hpp(5): Siehe Deklaration von 'RNG'
1>c:\users\sebastian\documents\visual studio 2013\projects\lunar defense\lunar defense\rng.inl(5): error C2244: 'RNG<T>::nextRandom': Keine Übereinstimmung für Funktionsdefinition mit vorhandener Deklaration gefunden
1> Definition
1> 'T RNG::nextRandom(const T &,const T &)'
1> Vorhandene Deklarationen
1> 'float RNG<T>::nextRandom(const float,const float)'
1> 'T RNG<T>::nextRandom(T &,T &)'
1>c:\users\sebastian\documents\visual studio 2013\projects\lunar defense\lunar defense\rng.cpp(4): error C2955: 'RNG' : Für die Verwendung von Klasse template ist eine template-Argumentliste erforderlich
1> c:\users\sebastian\documents\visual studio 2013\projects\lunar defense\lunar defense\rng.hpp(5): Siehe Deklaration von 'RNG'
1>c:\users\sebastian\documents\visual studio 2013\projects\lunar defense\lunar defense\rng.cpp(7): error C2910: 'RNG<T>::nextRandom': Kann nicht explizit spezialisiert werden
========== Erstellen: 0 erfolgreich, 1 fehlerhaft, 0 aktuell, 0 übersprungen ==========

Ich bin in Templates nicht ganz geübt, erst recht nicht in spezialisierten Funktionen. Kann mir hier jemand weiterhelfen?

Greets

Nim
Ich bin kein UserSideGoogleProxy. Und nein, dieses Forum ist kein UserSideGoogleProxyAbstractFactorySingleton.

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

2

11.04.2014, 16:42

Zitat

Hier die Dateien, die ich am Anfang hatte: [...]

Ich sehe den Sinn an dem ganzen Code nicht.
Während man früher möglicherweise wirklich genötigt war, solche Klassen zusammenzubauen um Zufallszahlen zu erhalten, bietet C++11 selbst bereits alles Notwendige. Mit einer zusätzlichen Wrapperklasse von dir machst du nur alle komplizier und eingeschränkter als es sein müsste.

Des Weiteren verstehe ich die Implementation selbst nicht. "Min" und "Max" sind so wohl Member als auch Parameter, nur die Member scheinst du nie zu nutzen. Der Sinn des Templateparameters "T" erschließt sich mir auch nicht ganz. Wenn die Funktion "nextRandom" verwendet wird, hat der Parameter keinerlei Auswirkungen. Möglicherweise wolltest du für "float" eine Spezialisierung erstellen, was allerdings so nicht geht. Du hast nur eine Überladung. Für Klassenspezialisierungen schaue in divsersen Tutorials im Internet.

Zitat

Im Chat wurde mir dann mitgeteilt, dass das Aufteilen von templates auf hpp und cpp nicht so einfach wäre und ich das ganze auf 3 Dateien aufteilen sollte.

Templateklassen lassen sich genauer gesagt nahezu gar nicht in Header und Quelldateien aufteilen.
Für einzelne Instanzen eines Templates mit dem entsprechenden Parameter sollte das zwar möglich sein, macht aber alles bloß komplizierter und schränkt die Wahl der Templateparameter ein. Insbesondere dann, wenn man mit Templates eh noch nicht so fit ist.
Ich würde bis auf wenige Ausnahmen einfach immer alle Funktionen im Header definieren, wie du es auch bei "setSeed" gemacht hast.
So ein Durcheinander mit Extradateien wie "inl" oder "cpp" brauchst du dann nicht.

Nimelrian

Alter Hase

  • »Nimelrian« ist der Autor dieses Themas

Beiträge: 1 216

Beruf: Softwareentwickler (aktuell Web/Node); Freiberuflicher Google Proxy

  • Private Nachricht senden

3

11.04.2014, 18:47

Das Problem ist, dass ich meine aktuellen random Funktionen in einer Util.hpp habe. Mit den neuen Random Klassen müsste ich allerdings entweder den Generator in der Util.hpp deklarieren (und globale Variablen mag ich nicht), oder ich erstelle bei jeder Erzeugung einer Zufallszahl einen neuen Seed und Generator, was auch nicht vorteilhaft ist. Deswegen die Wrapper Klasse. Dass die Definition jetzt schon Sinn macht, habe ich nicht behauptet, mir reicht es erstmal, eine spezialisierte Funktion für Floats zu haben.
Ich bin kein UserSideGoogleProxy. Und nein, dieses Forum ist kein UserSideGoogleProxyAbstractFactorySingleton.

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

4

11.04.2014, 19:03

Damit hast du das Problem allerdings nur verschoben.
Anstatt das jetzt der C++11 Generator direkt global oder per Instanz ist, gibt es mit deiner "RNG"-Klasse das selbe Problem.
Diese "Problematik" ist nicht an eine konkrete Klasse gebunden und rechtfertigt keinen Wrapper. (Auch wenn du "erstmal" nur dieses oder jenes brauchst)

Was bei deinem Problemfall besser ist, hängt einfach davon ab, was du machen willst.
Da die alten "rand"-Funktionen die du wohl früher benutzt hast automatisch mit einem globalen Status gearbeitet hat, wäre der einfache Ersatz ein globaler C++ Generator. Wenn die Zufallszahlen nicht deterministisch sein müssen, spricht prinzipiell auch nicht all zu viel dagegen. Mit hoher Wahrscheinlichkeit sind die C++11 Generatoren auch nicht unbedingt Threadsicher. "rand" war das jedoch auch alles nicht.

Die (in den meisten Fällen wohl eigentlich bessere) Alternative ist halt, das du den Generator in irgendeiner übergeordneten Klasse platzierst.
Eine eigene neue Klasse kann daran grundlegend erstmal nichts ändern.

Werbeanzeige