Wir sind dabei, alle unsere Compiler (in den nächsten zwei Jahren) auf C++ 11-fähige Compiler umzustellen.Ist dieses Muster für eine rückwärtskompatible Quellmigration von C++ 03 enum in C++ 11 enum-Klasse in Ordnung?
Unsere Kunden werden unsere Header verwenden, und wir sind jetzt in der Lage, Header für unsere neue API (mehr oder weniger von Grund auf) zu schreiben.
Also müssen wir zwischen C++ 03 enums (mit all ihren Warzen) wählen oder eine Wrapping-Klasse verwenden, um die C++ 11-Notation zu simulieren, weil wir diese Enums schließlich nach C + verschieben wollen +11.
Ist das "LikeEnum" -Idiom unten eine brauchbare Lösung, oder verbergen sich unerwartete Überraschungen dahinter?
template<typename def, typename inner = typename def::type>
class like_enum : public def
{
typedef inner type;
inner val;
public:
like_enum() {}
like_enum(type v) : val(v) {}
operator type() const { return val; }
friend bool operator == (const like_enum & lhs, const like_enum & rhs) { return lhs.val == rhs.val; }
friend bool operator != (const like_enum & lhs, const like_enum & rhs) { return lhs.val != rhs.val; }
friend bool operator < (const like_enum & lhs, const like_enum & rhs) { return lhs.val < rhs.val; }
friend bool operator <= (const like_enum & lhs, const like_enum & rhs) { return lhs.val <= rhs.val; }
friend bool operator > (const like_enum & lhs, const like_enum & rhs) { return lhs.val > rhs.val; }
friend bool operator >= (const like_enum & lhs, const like_enum & rhs) { return lhs.val >= rhs.val; }
};
die es uns ermöglichen, unsere Aufzählungen zu aktualisieren, ohne unerwünschte Änderungen in dem Benutzercode benötigt:
// our code (C++03) | our code C++11
// --------------------------------------+---------------------------
|
struct KlingonType | enum class Klingon
{ | {
enum type | Qapla,
{ | Ghobe,
Qapla, | Highos
Ghobe, | } ;
Highos |
} ; |
} ; |
|
typedef like_enum<KlingonType> Klingon ; |
|
// --------------------------------------+---------------------------
// client code (both C++03 and C++11)
void foo(Klingon e)
{
switch(e)
{
case Klingon::Qapla : /* etc. */ ; break ;
default : /* etc. */ ; break ;
}
}
Hinweis: Die LikeEnum wurde von der Note Type Safe Enum idiom
inspiriert 2 : Quellkompatibilität deckt Kompilierungsfehler wegen impliziter Konvertierung zu int nicht ab: Diese werden als unerwünscht betrachtet und der Client wird in adv benachrichtigt um die Ganzzahlkonvertierung explizit zu machen.
Machen Sie zwei von 'inner 'eine' template' Funktion, die SFINAE stellt sicher, dass der angeforderte Typ' inner 'ist, um Ein-Benutzer-implizite Konvertierungen zu vermeiden? Oder verwenden Sie einen Zwischentyp? Das Safe-Bool-Idiom und das Problem im Grunde ... (oder würde dieses Problem nicht für 'Enum's gelten?) – Yakk