我認爲編寫通用訪問者基類模板是一個簡單的練習。我們的目標是能夠寫C++中的通用訪問者基類模板 - 超載問題
typedef visitor<some_base, some_derived1, some_derived2> my_visitor;
...然後有my_visitor是一個類型,它的功能相當於
struct my_visitor {
virtual void visit(some_base&) {}
virtual void visit(some_derived1&) {}
virtual void visit(some_derived2&) {}
};
,我可以用實際的用處派生的訪問類繼承該類型層次結構,根據需要覆蓋不同的visit()版本。我希望它適用於任何具有任何繼承關係的類型,並且我不想使用任何使用type_info比較重新實現虛擬函數的黑客。這是我想出的:
#include <cstdlib>
#include <iostream>
#include <vector>
/** This is the generic part that would go in a visitor.hpp header. */
template <typename T> struct visitor_base {
virtual void visit(T&) {};
};
template <typename... T> struct visitor : visitor_base<T>... {};
/** This is the part that is specific to a certain type hierarchy. */
struct base;
struct derived1;
struct derived2;
typedef visitor<base, derived1, derived2> my_visitor;
/** This is the type hierarchy. */
struct base {
virtual void accept(my_visitor& v) { v.visit(*this); }
};
struct derived1 : base {
derived1() : i(42) {}
virtual void accept(my_visitor& v) { v.visit(*this); }
int i;
};
struct derived2 : base {
derived2() : f(2.79) {}
virtual void accept(my_visitor& v) { v.visit(*this); }
float f;
};
/** These are the algorithms. */
struct print_visitor : my_visitor {
void visit(base&) { std::cout<<"that was a base."<<std::endl; }
void visit(derived1& d) { std::cout<<"that was "<<d.i<<std::endl; }
void visit(derived2& d) { std::cout<<"that was "<<d.f<<std::endl; }
};
struct randomise_visitor : my_visitor {
void visit(derived1& d) { d.i = std::rand(); }
void visit(derived2& d) { d.f = std::rand()/float(RAND_MAX); }
};
int main() {
std::vector<base*> objects { new base, new derived1, new derived2,
new derived2, new base };
print_visitor p;
randomise_visitor r;
for (auto& o : objects) o->accept(p);
for (auto& o : objects) o->accept(r);
for (auto& o : objects) o->accept(p);
}
問題是,這不會編譯。 GCC說
silly_visitor.cpp: In member function ‘virtual void base::accept(my_visitor&)’:
silly_visitor.cpp:24:42: error: request for member ‘visit’ is ambiguous
silly_visitor.cpp:8:16: error: candidates are: void visitor_base<T>::visit(T&) [with T = derived2]
silly_visitor.cpp:8:16: error: void visitor_base<T>::visit(T&) [with T = derived1]
silly_visitor.cpp:8:16: error: void visitor_base<T>::visit(T&) [with T = base]
基本上,問題是,由於不同的訪問()成員函數在不同的類中聲明,他們不被視爲候選人重載只是模棱兩可成員訪問。強制編譯器考慮用於重載解析的繼承函數的一般技巧是在派生類中使用'using'語句重新聲明它們,但在這種情況下這是不可行的,因爲它會破壞它的整個泛型方面。
所以,顯然這並不像我想象的那麼容易。有任何想法嗎?
[在可變參數模板使用聲明】(http://stackoverflow.com/questions/7870498/using-declaration-in-variadic-template) – Xeo