我相信这是一个坏主意。假设我有一个很好的理由去做。我有一个成功使用静态多态传递消息的节点树。关键的是,每个节点不能连接到的节点类型,它只知道它传递的消息类型。为了遍历树,我使用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