2015-04-14 18 views
7

Ho un codice simile al seguente.Aumenta visitatore variante con un parametro aggiuntivo

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

MsgValue v; 

Invece di dire questo,

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

vorrei passare un parametro in più in questo modo: Ma operator() dà un errore di compilazione.

//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

Cosa vuoi fare con 'anotherStr'? – P0W

+1

Perché non passi 'anotherStr' al costruttore di' d_string_int_visitor' e poi usalo? – Nawaz

+0

Le soluzioni di Preatorian e Yakk non sono generiche; funzionano solo perché il tipo del parametro extra è uno dei tipi limitati. Questa è la cosiddetta visita multipla (multi). Se il tipo extra non era un tipo limitato, l'unica soluzione sarebbe utilizzare la variabile costruttore e membro, come sottolineato da Nawaz. – wmamrak

risposta

7

È possibile associare il string argomento extra al visitatore utilizzando std::bind. Innanzitutto, aggiungi il parametro std::string a tutti gli overload del visitatore operator().

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; 
    } 
}; 

Ora creare un visitatore a cui si è legato il secondo argomento string.

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

Live demo

Tuttavia, una soluzione migliore potrebbe essere quella di passare la stringa come argomento del costruttore del visitatore.

+0

Grazie Nawaz, Praetorian, ho avuto un punto cieco per qualche motivo per passarlo a d_string_int_visitor. Ma sono davvero contento poiché questa soluzione ha effettivamente ampliato la mia comprensione del boost bind. – Ivan

+0

Perché dovresti usare 'std :: bind' in C++ 14 per questo? – Yakk

+0

@Yakk Habit Suppongo (scrivo ancora C++ 03 al lavoro). Ma, IMHO, questa è una di quelle rare occasioni in cui la soluzione lambda non sembra molto più appetibile rispetto alla soluzione "bind". – 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); 

assumendo ogni sovraccarico di d_string_int_visitor in grado di gestire il parametro supplementare.

Come bonus, si può anche fare a meno della classe involucro, se si desidera:

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); 

dove creiamo un lambda anonima che inoltra a un insieme tradizionale di sovraccarichi di funzioni.

Il auto&& one e decltype(one)(one) è una tecnica per eseguire l'inoltro perfetto da un lambda (C++ 14). È possibile sostituire il secondo con std::forward<decltype(one)>(one), ma trovo la versione breve leggibile. A differenza di std::forward, fa la cosa "sbagliata" con i tipi di valore, ma sappiamo che one è un riferimento di valore lor.

+0

Si noti che questo richiede almeno Boost 1.58. –

Problemi correlati