Como implementar uma variante básica (e um visitante na variante) Modelo em C ++?
Pergunta
Eu tentei ler:
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"
mas ainda não entendo como as variantes são implementadas. Alguém pode colar um pequeno exemplo de como 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);
Obrigado!
Solução
Se eu tivesse que definir um objeto variante, provavelmente começaria com o seguinte:
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);
}
Em seguida, use Vetores MPL Para fazer a abordagem funcionar para mais do que apenas dois tipos diferentes.
No final, você pode escrever algo assim:
Variant<Type1, Type2> v;
class MyVisitor
{
public:
operator()(Type1);
operator()(Type2);
};
MyVisitor visitor;
v = Type1();
visit(visitor, v);
v = Type2();
visit(visitor, v);
NB: Não há chance de que esse código compila, mas isso descreve as idéias que eu usaria.
Outras dicas
EU acho Você está perguntando como usar variantes, não como implemento eles. Você pode querer olhar para o Aumente a documentação sobre variantes; Isso será muito mais útil do que olhar para o arquivo de cabeçalho.
Então seu exemplo pode parecer algo assim:
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);