Reputation: 311
I'm trying to implement visitor pattern for n-ary tree mutation. Currently i'm stuck with shared pointers. Mutator operates on each tree node and can return either pointer to a node itself w/o any changes, or a pointer to a copy of modified node (original node cannot be modified directly). But obviously i can't build a shared pointer from a raw pointer inside Visit
method, neither i can't make a shared pointer from this
inside a Mutate
method. The only idea that comes into my mind, is to create another class which will be holding pointer and pass this class pointer to visitor instead, but perhaps there is a better solution?
// Forward declarations
class ExpressionTreeMutator;
struct BaseExpr;
enum class ExpressionType {
kString,
kInt,
};
using ExprPtr = std::shared_ptr<BaseExpr>;
struct BaseExpr {
explicit BaseExpr(ExpressionType expression_type) : expression_type_(expression_type) {}
virtual ~BaseExpr() = default;
virtual ExprPtr Mutate(ExpressionTreeMutator* visitor) const = 0;
ExpressionType expression_type_;
};
// Curiously recurring template pattern
template<typename T>
struct Expr : public BaseExpr {
explicit Expr(ExpressionType expression_type) : BaseExpr(expression_type) {}
~Expr() override = default;
ExprPtr Mutate(ExpressionTreeMutator* visitor) const override;
};
struct String : public Expr<String> {
explicit String(std::string value) : Expr(ExpressionType::kString),
value_(std::move(value)) {}
std::string value_;
};
struct Int : public Expr<Int> {
explicit Int(int64_t value) : Expr(ExpressionType::kInt),
value_(value) {}
int64_t value_;
};
class ExpressionTreeMutator {
public:
virtual ~ExpressionTreeMutator() = default;
protected:
template<typename T>
friend
struct Expr;
virtual ExprPtr Visit(Int const* expr) {
// return expr ??? (in some cases return ptr as it is)
};
virtual ExprPtr Visit(String const* expr) {
// return String::Make(expr) ??? (make a copy)
};
};
template<typename T>
ExprPtr Expr<T>::Mutate(ExpressionTreeMutator* visitor) const {
return visitor->Visit(dynamic_cast<T const*>(this));
}
Upvotes: 3
Views: 216
Reputation: 939
As it is tagged C++20, I'd suggest to use std::variant and std::visit instead.
Otherwise, you can inherit from std::enable_shared_from_this, which allows to create shared_ptr from within methods of X.
You can also use mutate not to do the actual mutation, but to return appropriate function object that does the mutation and then pass the shared_ptr to this object.
Upvotes: 1