2012-02-16 15 views
7

Quiero construir boost::variant que contenga valores construidos por defecto, especificados con un índice de tipo, sin escribir mi propia instrucción de conmutación sobre el índice de tipo.¿Construir una variante de impulso que contenga un valor de tipo n en el índice de tipo de variante?

Me imagino que debe ser posible, de alguna manera, con MPL?

Sin embargo, para aclarar, el índice no es una expresión constante en tiempo de compilación.

El caso de uso es que necesito construir una variante que luego será reemplazada por una que contenga el valor correcto, pero en este momento solo conozco el índice de tipo. Piense en ello como un problema de deserialización perezosa.

+0

Como menciona MPL, creo que 'N' (el índice de tipo) es conocido en tiempo de compilación, sin embargo, la deserialización lenta sugiere que solo estará disponible en tiempo de ejecución -> ¿cuál es? –

+0

@MatthieuM. Esto sería imposible con el último. Espero lo primero, de lo contrario mi respuesta tampoco tiene valor. – pmr

+0

@MatthieuM. Ah, buen punto: solo está disponible en tiempo de ejecución. – James

Respuesta

11

Tiene que usar el 0de tipo variant::types. Esto le da una secuencia compatible con MPL que luego podemos usar con mpl::at y una plantilla para hacer nuestra oferta. Esto hace el truco:

#include <string> 
#include <boost/variant.hpp> 
#include <boost/mpl/at.hpp> 
#include <boost/mpl/int.hpp> 

template<typename U, typename V> 
void construct_in(V& v) { 
    v = U(); 
    // modern 
    // v = U{}; 
} 

int main() 
{ 
    typedef boost::variant<int, std::string> variant; 
    typedef boost::mpl::at<variant::types, boost::mpl::int_<1>>::type pos; 
    variant v; 
    // use type deduction 
    construct_in<pos>(v); 
    // does not throw, does work 
    std::string& s =boost::get<std::string>(v); 
    return 0; 
} 

Aquí va el tiempo de ejecución de la variante:

#include <string> 
#include <vector> 
#include <functional> 

#include <boost/variant.hpp> 
#include <boost/mpl/at.hpp> 
#include <boost/mpl/int.hpp> 
#include <boost/mpl/for_each.hpp> 

typedef boost::variant<int, std::string> variant; 
typedef variant::types types; 
typedef std::vector< std::function<void(variant&)> > fvec; 

template<typename U, typename V> 
void construct_in(V& v) { 
    v = U{}; 
} 

struct build_and_add { 
    fvec* funcs; 
    template<typename T> 
    void operator()(T) { 
    funcs->push_back(&construct_in<T, variant>); 
    } 
}; 


int main() 
{ 

    variant v; 
    std::vector< std::function<void(variant&)> > funcs; 

    // cannot use a lambda, would need to be polymorphic 
    build_and_add f = {&funcs}; 
    boost::mpl::for_each<types>(f); 

    // this is runtime! 
    int i = 1; 

    funcs[i](v); 
    // does not throw, does work 
    std::string& s =boost::get<std::string>(v); 
    return 0; 
} 

Es un poco arcano y necesitará algunos ajustes con variadic argumentos para ser verdaderamente genérico, pero hace lo que quiere . Alguien más necesita averiguar si esto da como resultado una explosión significativa del código .

+0

Disculpe la aclaración sobre el tipo de índice que se está ejecutando, pero no creo que esta respuesta sea inútil; sería posible ampliar esto para cambiar entre N índices constantes en tiempo de ejecución, donde solo se fija N en compilación de tiempo (¿e incluso se puede extraer de la variante, quizás?) – James

+0

@Autopulated No realmente, pero algo de magia negra podría ayudar. Piensa en la plantilla que usamos para la construcción. Podemos generar todas esas plantillas en tiempo de compilación y almacenarlas como objetos 'std :: function' en un vector y usar este vector en tiempo de ejecución para buscar lo que queremos construir. Trataré de hacer algo juntos, pero no sé qué tan bueno sería en términos de revelado de código, etc. – pmr

+0

@pmr: mi reacción instintiva fue utilizar la recursividad, pero un vector (o matriz desde N es constante) de apuntador a funciones parece dar una garantía de rendimiento mucho mejor (no depender de una eventual recursión final). Es posible que aún necesite recurrencia para la inicialización del vector, pero es algo único. –

Cuestiones relacionadas