我相信這是一個壞主意。假設我有一個很好的理由去做。我有一個成功使用靜態多態傳遞消息的節點樹。關鍵的是,每個節點不能連接到的節點類型,它只知道它傳遞的消息類型。爲了遍歷樹,我使用CRTP實現了訪問者模式。這適用於樹的第一級。混合雙派遣和靜態多態性
但是,當遍歷樹的第二層時,使用下面的AnyNode類刪除下一個節點的類型。我一直無法弄清楚如何從刪除類型轉換爲具體類型。下面的例子在測試中起作用,但我認爲這也可能是非常危險的,只是在內存恰好佈局的地方運氣。
似乎有一個問題,我必須在中刪除訪問者的類型,這在AnyNode::Concept::accept
中是完全已知的。但我無法弄清楚如何從概念模型在概念(我嘗試了協變虛擬cast
功能,但沒有工作)。而且我無法使用虛擬方法將類型訪問者傳遞給派生模型類,因爲虛擬方法無法進行模板化。
有沒有一種安全的方式可以撥打node.accept
並傳遞訪問者而不必刪除訪問者的類型,然後靜態地將其返回?有什麼方法可以在運行時將Concept降級到Model<T>
?有沒有更好的方法來解決這個問題?是不是有一些瘋狂的新的C + + 11的方式來解決這個問題,可能與SFINAE?這裏
class AnyNode
{
struct Concept
{
virtual ~Concept() = default;
template< typename V >
void accept(V & visitor)
{
acceptDispatch(&visitor);
}
virtual void acceptDispatch(VisitorBase *) = 0;
};
template< typename T >
struct Model : public Concept
{
Model(T &n) : node(n) {}
void acceptDispatch(VisitorBase * v) override
{
// dynamic cast doesn't work, probably for good reason
NodeVisitor<T>* visitor = static_cast< NodeVisitor<T>* >(v);
std::cout << "CAST" << std::endl;
if (visitor) {
std::cout << "WAHOO" << std::endl;
node.accept(*visitor);
}
}
private:
T &node;
};
std::unique_ptr<Concept> mConcept;
public:
template< typename T >
AnyNode(T &node) :
mConcept(new Model<T>(node)) {}
template< typename V >
void accept(V & visitor)
{
mConcept->accept(visitor);
}
};
編輯的訪問者基類,並舉例衍生遊客。派生的訪問者通過客戶端代碼實現(這是一個庫的一部分),所以基類不知道訪問者將實現什麼。我擔心這會分散中心問題,但希望它有助於解釋這個問題。除了在outlet_visitor::operator()
的AnyNode指針上調用->accept(visitor)
時,此處的所有內容都可以正常工作。
// Base class for anything that implements accept
class Visitable
{
public:
};
// Base class for anything that implements visit
class VisitorBase
{
public:
virtual ~VisitorBase() = default;
};
// Visitor template class
template< typename... T >
class Visitor;
template< typename T >
class Visitor<T> : public VisitorBase
{
public:
virtual void visit(T &) = 0;
};
template< typename T, typename... Ts >
class Visitor< T, Ts... > : public Visitor<Ts...>
{
public:
using Visitor<Ts...>::visit;
virtual void visit(T &) = 0;
};
template< class ... T >
class NodeVisitor : public Visitor<T...>
{
public:
};
// Implementation of Visitable for nodes
template< class V >
class VisitableNode : public Visitable
{
template< typename T >
struct outlet_visitor
{
T &visitor;
outlet_visitor(T &v) : visitor(v) {}
template< typename To >
void operator()(Outlet<To> &outlet)
{
for (auto &inlet : outlet.connections()) {
auto n = inlet.get().node();
if (n != nullptr) {
// this is where the AnyNode is called, and where the
// main problem is
n->accept(visitor);
}
}
}
};
public:
VisitableNode()
{
auto &_this = static_cast< V & >(*this);
_this.each_in([&](auto &i) {
// This is where the AnyNode is stored on the inlet,
// so it can be retrieved by the `outlet_visitor`
i.setNode(*this);
});
}
template< typename T >
void accept(T &visitor)
{
auto &_this = static_cast< V & >(*this);
std::cout << "VISITING " << _this.getLabel() << std::endl;
visitor.visit(_this);
// The outlets are a tuple, so we use a templated visitor which
// each_out calls on each member of the tuple using compile-time
// recursion.
outlet_visitor<T> ov(visitor);
_this.each_out(ov);
}
};
// Example instantiation of `NodeVistor<T...>`
class V : public NodeVisitor< Int_IONode, IntString_IONode > {
public:
void visit(Int_IONode &n) {
cout << "Int_IONode " << n.getLabel() << endl;
visited.push_back(n.getLabel());
}
void visit(IntString_IONode &n) {
cout << "IntString_IONode " << n.getLabel() << endl;
visited.push_back(n.getLabel());
}
std::vector<std::string> visited;
};
爲什麼'dynamic_cast'沒有工作? – 1201ProgramAlarm
是否有數量有限的模型或訪問者?他們可以在任何地方被枚舉嗎?什麼是「VisitorBase」?這些是3個問題,請全部回答3. – Yakk
爲了回答您的兩個問題,我添加了周圍的代碼。我希望這不是TMI。 @ 1201ProgramAlarm我認爲dynamic_cast不起作用,因爲'NodeVisitor < T >'只是訪問者的類層次結構的一部分。 – Ian