c++ - Virtual template functions: implementing the Visitor pattern with parameters -


i trying implement visitor pattern walking ast. have defined astnode can accept visitor, , allow visitor visit itself. example below contains 1 concrete implementation each of visitor , astnode.

class astnode;  template <class p, class r> class visitor {     public:         virtual ~visitor() {}         virtual r visit(astnode& node, p p) const = 0; };  class astnode {     public:         virtual ~astnode() {}         template <class p, class r>         virtual r accept(visitor<r, p>& v, p p) {             return v.visit(*this);         } };  class roman : public astnode {     public:         roman(numeral n, optional<accidental> a) : numeral(n), alteration(a) {};         const numeral numeral;         const optional<accidental> alteration; };  class tostringvisitor : public visitor<string, int> {     virtual string visit(roman& node, int param) {         string result = numeralstrings[node.numeral];         if (node.alteration.has_value()) result = accidentaltostring(node.alteration.value()) + result;         return result;     } }; 

then, can walk ast using this:

roman r; tostringvisitor tsv; // ... return r.accept(tsv, 42); 

as can see, trying use templates allow parameter , return value. however, compiler error:

 error: templates may not 'virtual'        virtual r accept(visitor<r, p>& v, p p) { 

i have vague understanding of why error. however, how can accomplish legally?

edit: don't think duplicate of this question, because i'm trying have accept return template type.

you error message because c++ forbids defining virtual template function. removing virtual keyword fix compilartion error.

i've finished writing parser/lexer , found using lambdas great time-saver.

here implementation of lambda visitors. compile in vs 2017, , should compile under gcc.

i got code talk: "c++now 2017: vittorio romeo “implementing variant visitation using lambdas"

file match.h

#pragma once  #include <type_traits> #include <variant>  template<typename tf, typename...tfs> struct overload_set : tf, overload_set<tfs...> {     using tf::operator();     using overload_set<tfs...>::operator();      template<typename tffwd, typename...tffwds>     constexpr overload_set(tffwd&& f, tffwds&&...rest)         : tf { std::forward<tffwd>(f) }         , overload_set<tfs...>{ std::forward<tffwds>(rest)... }     { } };  template<typename tf> struct overload_set<tf> : tf {     using tf::operator();      template<typename tffwd>     constexpr overload_set(tffwd&& f)         : tf { std::forward<tffwd>(f) }     { } };  template<typename...tfs> constexpr auto overload(tfs&...fs) {     return overload_set<std::remove_reference_t<tfs>...>(std::forward<tfs>(fs)...); }  template<typename visitor, typename...tvariants> constexpr decltype(auto) visit_recursively(visitor&& vis, tvariants&&...vars) {     return std::visit(         std::forward<visitor>(vis),         std::forward<tvariants>(variants)._data...     ); }  template<typename...tvariants> constexpr auto match(tvariants&&...vs) {     return [&vs...](auto&&...fs) //-> decltype(auto)     {         return std::visit(overload(std::forward<decltype(fs)>(fs)...), vs...);     }; } 

example @ interpreter level:

template<> std::string convertto<std::string>(const variant& v) {     return match(v)(         [](const std::string& s) { return s; },         [](const auto&) { throw internalerror("cannot convert type string"); return std::string{}; }     ); }  variant interpreter::evaluate(ast::rvalue & rv) {     // maps overloads types held variant type rvalue     return match(rv)(         [&](auto& x) { return evaluate(x); }     ); }  // recursion... variant evaluate(std::unique_ptr<ast::spheref>& rv) {     return match(rv->vec_) (         [](ast::vector4f& v) { return variant{ std::make_shared<vector4f>(std::move(v)) }; },         [&](std::vector<ast::rvalue>& v)     {         if (v.size() != 4)         {             throw internalerror{ "sphere must have 4 parameters" };         }         vector4f r;         r[0] = convertto<f32>(evaluate(v[0]));         r[1] = convertto<f32>(evaluate(v[1]));         r[2] = convertto<f32>(evaluate(v[2]));         r[3] = convertto<f32>(evaluate(v[3]));         return variant{ std::make_shared<vector4f>(std::move(r)) };     }     ); }  // cascading calls... objectref or = match(o->value_) (     [](identifier& id) -> objectref     {          return { std::make_shared<ast::identifier>(std::move(id)) };       },     [&](ast::objectvalueblock& bl) -> objectref     {         return match(std::move(evaluate(bl))) (             [](std::shared_ptr<object>&& x) { return objectref{ x }; },             [](std::shared_ptr<identifier>&& x) { return objectref{ x };},             [](auto&&) {                  throw internalerror{ "unexpected type in object array expansion" };                  return objectref{};              }         ); ); 

Comments

Popular posts from this blog

Is there a better way to structure post methods in Class Based Views -

performance - Why is XCHG reg, reg a 3 micro-op instruction on modern Intel architectures? -

jquery - Responsive Navbar with Sub Navbar -