Вам нужен полиморфизм во время выполнения?
struct object {
template <typename Visitor>
void accept( Visitor & v )
{
v( x );
v( a );
}
int x;
std::string a;
};
struct complex_object {
template <typename Visitor>
void accept( Visitor & v ) {
v( i );
o.accept(v); // [1]
}
int i;
object1 o;
};
struct DumpScreenVisitor {
void operator()( int x ) { std::cout << x << std::endl; }
template <typename char_t, typename traits_t, typename alloc_t>
void operator()( std::basic_string<char_t, traits_t, alloc_t> const & str )
{
std::cout << str << std::endl;
}
};
Вызов в [1] можно преобразовать в v( o )
с общим шаблоном operator()
для посетителей, который наименее специализирован:
template <typename O>
void DumpScreenVisitor::operator()( O & o )
{
o.accept( *this );
}
Но это может помешать реализации других посетителей (например, вышеупомянутый посетитель может быть реализован с помощью одного шаблонного метода):
struct DumpScreenVisitor {
template <typename T>
void operator()( T const & t ) {
std::cout << t << std::endl;
}
};
Так что в конце вам придется пойти на компромисс в любом случае.
Этот подход аналогичен реализации посетителя boost :: variable (вы можете захотеть взглянуть на него), с той разницей, что boost :: variable является отдельным классом, а не иерархией.