2016-04-15 12 views
1

Ich brauche eine Funktion, die den Typ von From To To (To und From sind Enums), aber eine Enum E1 kann nur auf E2 gegossen werden, muss ich einen Fehler erhalten, wenn der Benutzer versucht zum Beispiel E1 bis E3.C++ Cast spezifische Paare von Enums

Wie kann ich das tun? Vielen Dank!

+2

Gehen Sie mit Template-Spezialisierung –

+3

Können Sie mir ein Beispiel geben? –

Antwort

2

Eine mögliche Lösung: static_assert

template<typename From, typename To> 
static To map(From f) { 
    static_assert(!(std::is_same<From, E1>::value && std::is_same<To, E3>::value), 
        "cannot cast from E1 to E3"); 

    return static_cast<To>(f); 
} 

auto main() -> int { 
    E1 a; 
    const auto b = map<E1, E2>(a); // compiles 
    const auto c = map<E1, E3>(a); // won't compile 

    return 0; 
} 
+0

Es ist interessant Ihre Lösung, jedoch static_assert zur Kompilierzeit ausgewertet und From und To zur Laufzeit –

+0

Was ist los mit dem '->'? Ist das jetzt ein Teil von C++? Oh, ich sehe, Main ist eine Lambda-Funktion? Cool! – smac89

+0

Ionut Ja, richtig. Wie sieht Ihr Code aus, der die Funktion aufruft? @ Smac89 ja, du kannst main (...) jetzt so deklarieren :) – CppChris

1

Mit der Vorlagenspezialisierung können Sie angeben, wie für verschiedene Typen gearbeitet werden soll. Sehen Sie sich das folgende Beispiel an.

template<typename To, typename From> 
To map(From f){ 
    return static_cast<To>(f); 
} 

template<> 
E2 map(E1 f){ 
    return static_cast<E2>(f); 
} 

Wenn map() Funktion mit Typ E1 dann der spezielle Template-Funktion aufgerufen wird, wird anstelle der normalen Template-Funktion ausgeführt. Aber anders als Typ E1 wird normale Template-Funktion aufgerufen.

Dadurch wird der Benutzer gezwungen, nur E1 zu E2 zu übertragen. Wenn Sie eine Exception werfen möchten oder assert ändern Sie die Definition wie gewünscht.

0

Sie benötigen Template-Spezialisierung verwenden. Außerdem sollten Sie den Vorlagenparameter To als erstes Vorlagenargument verschieben, da dies der Rückgabetyp ist und der Compiler nicht in der Lage ist, daraus abzuleiten.

Erstellen Sie zunächst die primäre Template-Funktion, aber keine eine Implementierung davon:

template<typename To, typename From> 
To map(From from); 

nun tun Spezialisierung für die Zuordnungen, die Sinn machen:

template<> 
E2 map(E1 from) 
{ 
    return static_cast<E2>(from); 
} 

Wie Sie‘ Die Spezialisierung für die Mappings, die Sinn ergeben, liefert einen Fehler, wenn Sie versuchen, diejenigen aufzurufen, die dies nicht tun. Zum Beispiel auf VS2012, wenn Sie tun:

E3 value = map<E3>(e1_value); 

Sie erhalten eine „unresovled externes Symbol“ Fehlermeldung erhalten, da es für die Zuordnung keine Implementierung ist.

0

Unten ist eine Lösung, die Konzepte verwendet. Konzepte werden nach meinem Wissen nur in gcc6 implementiert, das immer noch experimentell ist.

#include <type_traits> 

enum E1{}; 
enum E2{}; 
enum E3{}; 

template <class T, class U> concept bool Same = std::is_same<T,U>::value; 

template<typename From, typename To> 
static To map(From f) 
requires !(Same<From, E1> && Same<To, E3>) 
{ 
    return static_cast<To>(f); 
} 

int main() 
{ 
    E1 e1; 
    E2 e2; 
    E3 e3; 

    map<E1, E2>(e1); // Ok 
    map<E1, E3>(e1); // Compile Error ! 
} 

zeigt Fehler wie folgt:

prog.cc: In function 'int main()': 
prog.cc:23:19: error: cannot call function 'To map(From) requires predicate(!((Same<From, E1>) && (Same<To, E3>))) [with From = E1; To = E3]' 
    map<E1, E3>(e1); 
       ^
prog.cc:10:11: note: constraints not satisfied 
static To map(From f) 
      ^~~ 

http://melpon.org/wandbox/permlink/mEG3Rl5jaMXj0GVg

mit experimentellen Version von gcc 6.0:

$ g ++ prog.cc -Wall -Wextra -I/usr /local/boost-1.60.0/include -std = gnu ++ 1z "-fconcepts"