2017-11-09 4 views
5

Ich habe eine std::variant, die ich in eine andere std::variant konvertieren möchte, die eine Super-Reihe seiner Typen hat. Gibt es eine Möglichkeit, das zu tun, als dass ich es einfach dem anderen zuweisen kann?Convert std :: Variante in eine andere Std :: Variante mit Super-Satz von Typen

template <typename ToVariant, typename FromVariant> 
ToVariant ConvertVariant(const FromVariant& from) { 
    ToVariant to = std::visit([](auto&& arg) -> ToVariant {return arg ; }, from); 
    return to; 
} 

int main() 
{ 
    std::variant<int , double> a; 
    a = 5; 
    std::variant <std::string, double, int> b; 
    b = ConvertVariant<decltype(b),decltype(a)>(a); 
    return 0; 
} 

Ich mag würde die Lage sein, einfach b = a zu schreiben, um die Umwandlung eher zu tun, als durch diesen komplexen Guss Setup gehen. Ohne den Namensraum std zu verschmutzen.

Edit: Einfach b = a Schreiben gibt den folgenden Fehler:

error C2679: binary '=': no operator found which takes a right-hand operand of type 'std::variant<int,double>' (or there is no acceptable conversion) 

note: while trying to match the argument list '(std::variant<std::string,int,double>, std::variant<int,double>)' 
+1

Wenn 'U' ist Universum aller Typen und P hat U, ist nicht P gleich U? Ich habe Probleme zu verstehen, welches Problem Sie versuchen zu lösen, vielleicht bin ich dumm: | – P0W

+0

Versuchen Sie, 'b = a' direkt zu kompilieren, um das Problem zu sehen. –

+0

Der Fehler lautet wie folgt: Fehler C2679: binäre '=': kein Operator gefunden, die einen rechten Operanden vom Typ 'Std :: Variante ' (oder es gibt keine akzeptable Konvertierung) Hinweis: beim Versuch zu passe die Argumentliste an (std :: variant , std :: variant ) ' – Bomaz

Antwort

3

Dies ist eine Implementierung der zweiten Option des Yakk:

template <class... Args> 
struct variant_cast_proxy 
{ 
    std::variant<Args...> v; 

    template <class... ToArgs> 
    operator std::variant<ToArgs...>() const 
    { 
     return std::visit([](auto&& arg) -> std::variant<ToArgs...> { return arg ; }, 
          v); 
    } 
}; 

template <class... Args> 
auto variant_cast(const std::variant<Args...>& v) -> variant_cast_proxy<Args...> 
{ 
    return {v}; 
} 

Sie zur Feinabstimmung es Semantik für die Weiterleitung wünschen könnte.

Und wie man seine Verwendung finden kann, ist einfach:

std::variant<int, char> v1 = 24; 
std::variant<int, char, bool> v2; 

v2 = variant_cast(v1); 
0

Optionen:

  • Schreiben Sie Ihre eigene variant Typ, möglicherweise von std::variant vererben, dass die Art und Weise Sie operator= und Konstruktion implementiert wollen . Etwas Arbeit muss getan werden, weil die Konstruktoren variant SFINAE-Tricks ausführen können, die mit Ihrem Variant-Typ nicht richtig funktionieren; Zu diesem Zweck möchten Sie eine SFINAE-Weiterleitung an die Basisvariante selbst vornehmen, anstatt nackte using Deklarationen.

  • Schreiben Sie eine bessere ConvertVariant, für die die Quell-/Zieltypen nicht aufgelistet werden müssen. Sie würden einen Convert-Helper-Schablonentyp zurückgeben, der die Quellvariante enthält, die eine operator std::variant<Ts...>()&& hat, die etwas sehr ähnlich Ihrem ConvertVariant aufruft.

Verwandte Themen