2015-04-14 11 views
7

Ich habe Code, der unten ähnelt.Boost Variante Besucher mit einem zusätzlichen Parameter

typedef uint32_t IntType; 
typedef IntType IntValue; 
typedef boost::variant<IntValue, std::string> MsgValue; 

MsgValue v; 

Statt dies zu sagen:

IntValue value = boost::apply_visitor(d_string_int_visitor(), v); 

Ich möchte einen zusätzlichen Parameter wie folgt weitergeben müssen: Aber Operator() gibt einen Compiler-Fehler.

//This gives an error since the overload below doesn't work. 
IntValue value = boost::apply_visitor(d_string_int_visitor(), v, anotherStr); 

class d_string_int_visitor : public boost::static_visitor<IntType> 
{ 
public: 
    inline IntType operator()(IntType i) const 
    { 
     return i; 
    } 

    inline IntValue operator()(const std::string& str) const noexcept 
    { 
     // code in here 
    } 

    //I want this, but compiler error. 
    inline IntValue operator()(const std::string& str, const std::string s) const noexcept 
    { 
     // code in here 
    } 
}; 
+0

Was möchten Sie mit 'anotherStr' machen? – P0W

+1

Warum übergibt man 'anotherStr' an den Konstruktor von' d_string_int_visitor' und benutzt es dann? – Nawaz

+0

Lösungen von Preatorian und Yakk sind nicht generisch; Sie funktionieren nur, weil der Typ des zusätzlichen Parameters einer der beschränkten Typen ist. Dies ist so genannte binäre (Multi) Visitation. Wenn der zusätzliche Typ kein beschränkter Typ wäre, wäre die einzige Lösung, den Konstruktor und die Elementvariable zu verwenden, wie von Nawaz hervorgehoben. – wmamrak

Antwort

7

Sie können die zusätzliche string Argument an die Besucher binden std::bind verwenden. Fügen Sie zuerst den Parameter std::string zu allen operator() Überladungen des Besuchers hinzu.

class d_string_int_visitor : public boost::static_visitor<IntType> 
{ 
public: 
    inline IntType operator()(IntType i, const std::string& s) const 
    { 
     return i; 
    } 

    inline IntValue operator()(const std::string& str, const std::string& s) const noexcept 
    { 
     // code in here 
     return 0; 
    } 
}; 

Jetzt ein Besucher erstellen, auf die Sie haben die zweite string Argument gebunden.

auto bound_visitor = std::bind(d_string_int_visitor(), std::placeholders::_1, "Hello World!"); 
boost::apply_visitor(bound_visitor, v); 

Live demo

Allerdings wäre eine bessere Lösung als die Zeichenfolge des Besuchers Konstruktorargument zu übergeben.

+0

Dank Nawaz, Praetorian, hatte ich aus irgendeinem Grund einen blinden Fleck, um es an d_string_int_visitor zu übergeben. Aber ich bin wirklich froh, da diese Lösung mein Verständnis von Boost Bind erweitert hat. – Ivan

+0

Warum würden Sie 'std :: bind' in C++ 14 dafür verwenden? – Yakk

+0

@Yakk Habit Ich denke (ich schreibe immer noch C++ 03 bei der Arbeit). Aber, meiner Meinung nach, ist dies einer dieser seltenen Fälle, in denen die Lambda-Lösung im Vergleich zur "Bind" -Lösung nicht viel schmackhafter erscheint. – Praetorian

3
typedef uint32_t IntType; 
typedef IntType IntValue; 
typedef boost::variant<IntValue, std::string> MsgValue; 

MsgValue v; 

IntValue value = boost::apply_visitor([&](auto&& one){ 
    return d_string_int_visitor{}(decltype(one)(one), anotherStr); 
}, v); 

unter der Annahme, jede Überlastung von d_string_int_visitor können die zusätzlichen Parameter behandeln.

Als Bonus können Sie auch mit der Verpackung Klasse abschaffen, wenn Sie wollen:

IntValue to_int_value(IntValue v, std::string const& format) { return v; } 
IntValue to_int_value(std::string const& str, std::string const& format); 

IntValue value = boost::apply_visitor([&](auto&& one){ 
    return to_int_value(decltype(one)(one), anotherStr); 
}, v); 

wo wir eine anonyme Lambda erstellen, die zu einem traditionellen Satz von Funktions Überlastungen weiterleitet.

Die auto&& one und decltype(one)(one) ist eine Technik, um perfekte Weiterleitung von einem Lambda (C++ 14) zu tun. Du könntest die zweite durch std::forward<decltype(one)>(one) ersetzen, aber ich finde die kurze Version lesbar. Im Gegensatz zu std::forward macht es die "falsche" Sache mit Werttypen, aber wir wissen, dass one eine l oder r-Wert-Referenz ist.

+0

Beachten Sie, dass dies mindestens Boost 1.58 erfordert. –

Verwandte Themen