Cómo implementar una variante básica (y un visitante en la variante) de plantillas de C ++?
Pregunta
He tratado:
http://www.boost.org/doc/libs/1_41_0/boost/variant.hpp
http://www.codeproject.com/KB/cpp/TTLTyplist.aspx
and chapter 3 of "Modern C++ Design"
pero aún no entienden cómo se implementan las variantes. ¿Alguien puede pegar un pequeño ejemplo de cómo definir algo como:
class Foo {
void process(Type1) { ... };
void process(Type2) { ... };
};
Variant<Type1, Type2> v;
v.somethingToSetupType1 ...;
somethingToTrigger process(Type1);
v.somethingToSetupType2 ...;
somethingToTrigger process(Type2);
Gracias!
Solución
Si tuviera que definir un objeto variante, probablemente comenzar con el siguiente:
template<typename Type1, typename Type2>
class VariantVisitor;
template<typename Type1, typename Type2>
class Variant
{
public:
friend class VariantVisitor<Type1, Type2>;
Variant();
Variant(Type1);
Variant(Type2);
// + appropriate operators =
~Variant(); // deal with memory management
private:
int type; // 0 for invalid data, 1 for Type1, 2 for Type2
void* data;
};
template<typename Visitor, typename Type1, typename Type2>
class VariantVisitor
{
private:
Visitor _customVisitor;
public:
void doVisit(Variant<Type1, Type2>& v)
{
if( v.type == 1 )
{
_customVisitor( *(Type1*)(v.data));
}
else if( v.type == 2 )
{
_customVisitor( *(Type2*)(v.data));
}
else
{
// deal with empty variant
}
}
};
template<typename Visitor, typename Type1, typename Type2>
void visit( Visitor visitor, Variant<Type1, Type2> v )
{
VariantVisitor<Visitor, Type1, Type2>(visitor).doVisit(v);
}
a continuación, utilizar MPL vectores para hacer que el enfoque para algo más que dos tipos diferentes.
Al final, se podría escribir algo como esto:
Variant<Type1, Type2> v;
class MyVisitor
{
public:
operator()(Type1);
operator()(Type2);
};
MyVisitor visitor;
v = Type1();
visit(visitor, v);
v = Type2();
visit(visitor, v);
Nota:. No hay ninguna posibilidad de que este código se compila, pero esto describe las ideas que haría uso
Otros consejos
pensar usted está pidiendo la forma de uso variantes, no la forma de implemento ellos. Es posible que desee ver en la href="http://www.boost.org/doc/libs/1_41_0/doc/html/variant.html" rel="nofollow noreferrer"> documentación impulso ; esto será mucho más útil que mirar el archivo de cabecera.
A continuación, el ejemplo podría ser algo como esto:
class v_visitor : public boost::static_visitor
{
public:
void operator()(Type1 &t) const {...}
void operator()(Type2 &t) const {...}
};
v = Type1(...);
boost::apply_visitor(v_visitor(), v);