Und auch ... Ich möchte keine Funktionszeiger verwenden, ich möchte die Funktion selbst direkt verwenden (damit es inline sein kann oder andere Optimierungen zutreffen).Was ist eine Alternative zu Merkmalen für die Auswahl zwischen zwei verschiedenen benannten Funktionen?
Angenommen: Ich habe eine Template-Funktion/Klasse, die einige mathematische Sachen berechnen wird, und der Template-Parameter ist der Integraltyp, der unsigned int32_t
oder unsigned int64_t
sein könnte.
Irgendwann brauche ich Zufallszahlen, also brauche ich einen Generator, und in dem einen Fall werde ich mt19937
und in den anderen mt19937_64
verwenden. Die Namen der tatsächlichen Typen sind also unterschiedlich, aber ich muss einen auswählen und ihn im Quellcode schreiben.
Offensichtlich würde eine Merkmalsklasse auf dem integralen Typ gut funktionieren (und das mache ich jetzt). Aber es scheint mir für diese einmalige Verwendung Syntax-mäßig schwergewichtig zu sein, und auch etwas nicht-lokal (w.r.t. Lesen des Quellcodes, wenn Sie verstehen, was ich meine).
Ein anderer Ansatz wäre, die Verwendung des Generators in einer (generischen) Funktion einzukapseln und vollständige Spezialisierungen für meine beiden ganzzahligen Typen bereitzustellen. Und das ist eigentlich in Ordnung.
Aber: Gibt es andere Alternativen? Gibt es irgendeine Art von Kompilierzeit "if" oder "switch" (nicht ganz enable-if
, die das Instanziieren von Schablonen aktiviert/deaktiviert), die ich hier benutzen kann? Oder etwas anderes (vielleicht sogar einfacher als Template-Metaprogrammierung, die ich gerade nicht sehe)?
(PS Bitte nicht aufgehängt auf mt19937
& mt19937_64
- Ich weiß, diejenigen beide Aliase einen Typs sind ich mich mit meinem integralen Typ instanziiert könnte - aber ich die Standard-Definitionen mit ihrem großen Satz verwendet viel lieber hatte von ganz magischen Zahlen plus ich bin nicht nur interessiert an mt19937
/mt19937_64
aber ähnlichen Fällen auch)
Hier ist, was der Code für meine Züge Klasse zur Zeit wie folgt aussieht:..
template <class Base>
struct traits { };
template <>
struct traits<unsigned __int32>
{
using base_t = unsigned __int32;
static const int nbits = std::numeric_limits<base_t>::digits;
using random_engine_t = std::mt19937;
...
};
template <>
struct traits<unsigned __int64>
{
using base_t = unsigned __int64;
static const int nbits = std::numeric_limits<base_t>::digits;
using random_engine_t = std::mt19937_64;
...
};
Bitte geben Sie den Code ein, den Sie für Merkmale verwenden. –
Was stimmt nicht mit den Eigenschaften? Benötigen Sie nur die Eigenschaften :: random_engine_t an genau einer Stelle, so dass Sie das Muster nicht mögen? –
Barry
Ziemlich viel, aber auch, dass das Boilerplate vom Point-of-Use entfernt ist. Das heißt, Sie müssen einen Namen für die Abstraktion erfinden und sich daran erinnern, anstatt nur die beiden ursprünglichen Namen in-line/in-place zu verwenden, wo Sie sie verwenden möchten. (Natürlich umgeben von einer zusätzlichen Syntax, die hoffentlich "einigermaßen leicht zu lesen" ist für einige C++ - relative Werte von "vernünftig".) – davidbak