Last active
August 29, 2015 14:01
-
-
Save rhysd/3b73599071bb6876c2ea to your computer and use it in GitHub Desktop.
enable to return value by visitor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <memory> | |
#include <string> | |
#include <type_traits> | |
#include <cassert> | |
#include <iostream> | |
#include <boost/any.hpp> | |
// visitor のコンストラクタで visit してはどうか | |
template<class T> | |
using enable_if_void = typename std::enable_if< | |
std::is_void<T>::value | |
, T | |
>::type; | |
template<class T> | |
using disable_if_void = typename std::enable_if< | |
!std::is_void<T>::value | |
, T | |
>::type; | |
// Forward declaration for test nodes | |
struct char_literal; | |
struct float_literal; | |
struct visitor_holder_base { | |
virtual void visit(char_literal const& lit) = 0; | |
virtual void visit(char_literal &lit) = 0; | |
virtual void visit(float_literal const& lit) = 0; | |
virtual void visit(float_literal &lit) = 0; | |
// ... | |
// FIXME: So many pure virtual functions | |
virtual ~visitor_holder_base() | |
{} | |
}; | |
// Node: ResultType should be default constructible | |
template<class Visitor, class ResultType> | |
struct visitor_holder : visitor_holder_base { | |
Visitor &v; | |
ResultType result; | |
void visit(char_literal const& lit) override { result = v(lit); } | |
void visit(char_literal &lit) override { result = v(lit); } | |
void visit(float_literal const& lit) override { result = v(lit); } | |
void visit(float_literal &lit) override { result = v(lit); } | |
// ... | |
// FIXME: So many virtual functions | |
visitor_holder(Visitor &v) | |
: v(v) | |
{} | |
~visitor_holder() override | |
{} | |
}; | |
template<class Visitor> | |
struct visitor_holder<Visitor, void> : visitor_holder_base { | |
Visitor &v; | |
void visit(char_literal const& lit) override { v(lit); } | |
void visit(char_literal &lit) override { v(lit); } | |
void visit(float_literal const& lit) override { v(lit); } | |
void visit(float_literal &lit) override { v(lit); } | |
// ... | |
// FIXME: So many virtual functions | |
visitor_holder(Visitor &v) | |
: v(v) | |
{} | |
~visitor_holder() override | |
{} | |
}; | |
// Node: ResultType should be default constructible | |
template<class Visitor, class ResultType> | |
struct const_visitor_holder : visitor_holder_base { | |
Visitor const& v; | |
ResultType result; | |
void visit(char_literal const& lit) override { result = v(lit); } | |
void visit(char_literal &lit) override { result = v(lit); } | |
void visit(float_literal const& lit) override { result = v(lit); } | |
void visit(float_literal &lit) override { result = v(lit); } | |
// ... | |
// FIXME: So many virtual functions | |
const_visitor_holder(Visitor const& v) | |
: v(v) | |
{} | |
~const_visitor_holder() override | |
{} | |
}; | |
template<class Visitor> | |
struct const_visitor_holder<Visitor, void> : visitor_holder_base { | |
Visitor const& v; | |
void visit(char_literal const& lit) override { v(lit); } | |
void visit(char_literal &lit) override { v(lit); } | |
void visit(float_literal const& lit) override { v(lit); } | |
void visit(float_literal &lit) override { v(lit); } | |
// ... | |
// FIXME: So many virtual functions | |
const_visitor_holder(Visitor const& v) | |
: v(v) | |
{} | |
~const_visitor_holder() override | |
{} | |
}; | |
class visitor { | |
public: | |
std::shared_ptr<visitor_holder_base> const holder; | |
template<class AnyVisitor> | |
explicit visitor(AnyVisitor const& v) | |
: holder(std::make_shared<const_visitor_holder<AnyVisitor, typename AnyVisitor::result_type>>(v)) | |
{} | |
template<class AnyVisitor> | |
explicit visitor(AnyVisitor &v) | |
: holder(std::make_shared<visitor_holder<AnyVisitor, typename AnyVisitor::result_type>>(v)) | |
{} | |
// Note: remain the result of visit in a holder | |
template<class T> | |
void visit(T &node) | |
{ | |
holder->visit(node); | |
} | |
// Note: remain the result of visit in a holder | |
template<class T> | |
void visit(T const& node) const | |
{ | |
holder->visit(node); | |
} | |
}; | |
class node { | |
struct node_holder_base { | |
// Interfaces here | |
virtual void apply(visitor const& v) const = 0; | |
virtual void apply(visitor &v) = 0; | |
virtual ~node_holder_base() | |
{} | |
}; | |
template<class Node> | |
struct node_holder : node_holder_base { | |
Node node; | |
node_holder(Node const& node) | |
: node(node) | |
{} | |
node_holder(Node && node) | |
: node(node) | |
{} | |
void apply(visitor const& v) const override | |
{ | |
v.visit(node); | |
} | |
void apply(visitor &v) override | |
{ | |
v.visit(node); | |
} | |
~node_holder() override | |
{} | |
}; | |
std::shared_ptr<node_holder_base> holder; | |
public: | |
template<class AnyNode> | |
node(AnyNode const& n) | |
: holder(std::make_shared<node_holder<AnyNode>>(n)) | |
{} | |
template<class V> | |
enable_if_void<typename V::result_type> | |
apply(V const& v) const | |
{ | |
holder->apply(visitor{v}); | |
} | |
template<class V> | |
disable_if_void<typename V::result_type> | |
apply(V const& v) const | |
{ | |
visitor internal_visitor{v}; | |
holder->apply(internal_visitor); | |
auto const dispatched = std::dynamic_pointer_cast<const_visitor_holder<V, typename V::result_type>>(internal_visitor.holder); | |
assert(dispatched); | |
return dispatched->result; | |
} | |
template<class V> | |
enable_if_void<typename V::result_type> | |
apply(V &v) | |
{ | |
holder->apply(visitor{v}); | |
} | |
template<class V> | |
disable_if_void<typename V::result_type> | |
apply(V &v) | |
{ | |
visitor internal_visitor{v}; | |
holder->apply(internal_visitor); | |
auto const dispatched = std::dynamic_pointer_cast<visitor_holder<V, typename V::result_type>>(internal_visitor.holder); | |
assert(dispatched); | |
return dispatched->result; | |
} | |
}; | |
#include <iostream> | |
// Test nodes | |
struct char_literal { | |
char value; | |
}; | |
struct float_literal { | |
float value; | |
}; | |
template<class T> | |
struct ast_visitor { | |
using result_type = T; | |
}; | |
// Test visitors | |
struct printer : ast_visitor<void> { | |
int i = 0; | |
template<class T> | |
void operator()(T const& t) noexcept | |
{ | |
std::cout << "print node: " << t.value << std::endl; | |
i++; | |
} | |
}; | |
struct stringizer : ast_visitor<std::string> { | |
template<class T> | |
std::string operator()(T const& t) const noexcept | |
{ | |
return std::to_string(t.value); | |
} | |
}; | |
int main() | |
{ | |
node n1 = char_literal{'c'}; | |
node n2 = float_literal{3.14}; | |
// visitor which returns void | |
printer p; | |
n1.apply(p); | |
n2.apply(p); | |
std::cout << p.i << std::endl; | |
n1.apply(printer{}); | |
std::cout << n1.apply(stringizer{}) << std::endl; | |
std::cout << n2.apply(stringizer{}) << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment