使用参数从基函数指针调用基方法
Call base method from base function pointer with arguments
我正在使用访问者模式来遍历和打印我正在操作的树的子节点。为了缩进打印,我指定了如下样式的缩进级别:
printCurrent();
indentLevel(); // increases static variable
Visitor::visit(elem); // which then prints the children's node data
unindentLevel(); // decreases static variable
为了让它更好,我想实现一个函数,它接受带有参数 elem
的 Visitor::visit
并自动处理预操作 (indentLevel()
) 和 post-动作(unindentLevel()
).
在实现该函数之前,我需要定义一个函数指针,用作该函数的参数。但是,我未能指定指针的参数。例如,让我们看一下从 Visitor
:
派生的 PrintVisitor
void PrintVisitor::visit(BinaryExpr &elem) {
std::cout << formatOutputStr({elem.getNodeName()});
this->incrementLevel();
Visitor::visit(elem); // <-- this is where I want to create a function pointer to
this->decrementLevel();
}
这个想法基本上是 PrintVisitor
完成与打印相关的所有事情,所有其他逻辑(例如,遍历逻辑)在基础 class Visitor
中实现。因此 PrintVisitor::visit
需要执行它的特定操作(例如,通过 formatOutputStr 打印)然后执行 Visitor::visit
方法:
void PrintVisitor::visit(BinaryExpr &elem) {
std::cout << formatOutputStr({elem.getNodeName()});
void (Visitor::*myPt)(BinaryExpr&) = &Visitor::visit; // declare function pointer
executeIndented(myPt, elem); // pass function pointer myPt
}
// ...
void executeIndented("Function f", "FunctionArgs elem") {
// pre-action
this->incrementLevel();
// main action: call function pointer
(Visitor().*f)(elem); // call function pointer with arg
//post-action
this->decrementLevel();
}
我的目标是以某种方式实现在每个 PrintVisitor::visit
方法中始终调用预操作和 post 操作。为此,我认为将这些预操作和 post 操作封装到另一个函数 executeIndented
中是有意义的,它确保了
(Visitor().*myPt)(elem);
的语法对我来说有点奇怪,这真的是使用我的函数指针调用带有参数 elem
的(基本)函数 Visitor::visit
的正确方法吗myPt
?
// 编辑
使用 (Visitor(*this).*myPt)(elem);
也可以。这两种方式有什么区别,哪一种更受青睐?
// 编辑2
希望现在对我要实现的目标的描述更加清楚。
据我了解,你应该有这样的东西:
struct TraversalVisitor : IVisitor
{
void visit(BinaryExpr &elem) final
{
pre_traversal_action(elem);
visit(elem.lhs);
action(elem);
visit(elem.rhs);
post_traversal_action(elem);
}
virtual void pre_traversal_action(BinaryExpr &elem) { /*Nothing */ }
virtual void action(BinaryExpr &elem) { /*Nothing */ }
virtual void post_traversal_action(BinaryExpr &elem) { /*Nothing */ }
void visit(UnaryExpr &elem) final;
// ...
};
struct PrintVisitor : TraversalVisitor
{
void pre_traversal_action(BinaryExpr &elem) override {
std::cout << formatOutputStr({elem.getNodeName()});
incrementLevel();
}
//void action(BinaryExpr &elem) override { /*Nothing */ }
void post_traversal_action(BinaryExpr &elem) override { decrementLevel(); }
// ...
private:
void formatOutputStr(const std::string&);
void incrementLevel();
void decrementLevel();
// ...
};
而您尝试实现类似的东西:
struct Visitor : IVisitor
{
virtual visit(BinaryExpr &elem)
{
visit(elem.lhs);
visit(elem.rhs);
}
// ...
};
struct PrintVisitor : Visitor
{
private:
void formatOutputStr(const std::string&);
void incrementLevel();
void decrementLevel();
void executeIndented(Expr& elem) {
incrementLevel(); // pre-action
// Traversal
Visitor::visit(elem);
decrementLevel(); // post-action
}
void visit(BinaryExpr &elem) override {
std::cout << formatOutputStr({elem.getNodeName()});
executeIndented(elem);
}
// ...
};
你的尝试,IMO,只是因式分解 PrintVisitor
,没有强制执行一些遍历策略。
我正在使用访问者模式来遍历和打印我正在操作的树的子节点。为了缩进打印,我指定了如下样式的缩进级别:
printCurrent();
indentLevel(); // increases static variable
Visitor::visit(elem); // which then prints the children's node data
unindentLevel(); // decreases static variable
为了让它更好,我想实现一个函数,它接受带有参数 elem
的 Visitor::visit
并自动处理预操作 (indentLevel()
) 和 post-动作(unindentLevel()
).
在实现该函数之前,我需要定义一个函数指针,用作该函数的参数。但是,我未能指定指针的参数。例如,让我们看一下从 Visitor
:
PrintVisitor
void PrintVisitor::visit(BinaryExpr &elem) {
std::cout << formatOutputStr({elem.getNodeName()});
this->incrementLevel();
Visitor::visit(elem); // <-- this is where I want to create a function pointer to
this->decrementLevel();
}
这个想法基本上是 PrintVisitor
完成与打印相关的所有事情,所有其他逻辑(例如,遍历逻辑)在基础 class Visitor
中实现。因此 PrintVisitor::visit
需要执行它的特定操作(例如,通过 formatOutputStr 打印)然后执行 Visitor::visit
方法:
void PrintVisitor::visit(BinaryExpr &elem) {
std::cout << formatOutputStr({elem.getNodeName()});
void (Visitor::*myPt)(BinaryExpr&) = &Visitor::visit; // declare function pointer
executeIndented(myPt, elem); // pass function pointer myPt
}
// ...
void executeIndented("Function f", "FunctionArgs elem") {
// pre-action
this->incrementLevel();
// main action: call function pointer
(Visitor().*f)(elem); // call function pointer with arg
//post-action
this->decrementLevel();
}
我的目标是以某种方式实现在每个 PrintVisitor::visit
方法中始终调用预操作和 post 操作。为此,我认为将这些预操作和 post 操作封装到另一个函数 executeIndented
中是有意义的,它确保了
(Visitor().*myPt)(elem);
的语法对我来说有点奇怪,这真的是使用我的函数指针调用带有参数 elem
的(基本)函数 Visitor::visit
的正确方法吗myPt
?
// 编辑
使用 (Visitor(*this).*myPt)(elem);
也可以。这两种方式有什么区别,哪一种更受青睐?
// 编辑2 希望现在对我要实现的目标的描述更加清楚。
据我了解,你应该有这样的东西:
struct TraversalVisitor : IVisitor
{
void visit(BinaryExpr &elem) final
{
pre_traversal_action(elem);
visit(elem.lhs);
action(elem);
visit(elem.rhs);
post_traversal_action(elem);
}
virtual void pre_traversal_action(BinaryExpr &elem) { /*Nothing */ }
virtual void action(BinaryExpr &elem) { /*Nothing */ }
virtual void post_traversal_action(BinaryExpr &elem) { /*Nothing */ }
void visit(UnaryExpr &elem) final;
// ...
};
struct PrintVisitor : TraversalVisitor
{
void pre_traversal_action(BinaryExpr &elem) override {
std::cout << formatOutputStr({elem.getNodeName()});
incrementLevel();
}
//void action(BinaryExpr &elem) override { /*Nothing */ }
void post_traversal_action(BinaryExpr &elem) override { decrementLevel(); }
// ...
private:
void formatOutputStr(const std::string&);
void incrementLevel();
void decrementLevel();
// ...
};
而您尝试实现类似的东西:
struct Visitor : IVisitor
{
virtual visit(BinaryExpr &elem)
{
visit(elem.lhs);
visit(elem.rhs);
}
// ...
};
struct PrintVisitor : Visitor
{
private:
void formatOutputStr(const std::string&);
void incrementLevel();
void decrementLevel();
void executeIndented(Expr& elem) {
incrementLevel(); // pre-action
// Traversal
Visitor::visit(elem);
decrementLevel(); // post-action
}
void visit(BinaryExpr &elem) override {
std::cout << formatOutputStr({elem.getNodeName()});
executeIndented(elem);
}
// ...
};
你的尝试,IMO,只是因式分解 PrintVisitor
,没有强制执行一些遍历策略。