https://github.com/thelartians/revisited
🧑🤝🧑 The visitor pattern revisited. An inheritance-aware acyclic visitor template, any and any-function templates.
https://github.com/thelartians/revisited
acyclic any anyfunction compile-time cplusplus cpp fast function inheritance multimethods multiple-dispatch template visitor visitor-pattern
Last synced: 5 months ago
JSON representation
🧑🤝🧑 The visitor pattern revisited. An inheritance-aware acyclic visitor template, any and any-function templates.
- Host: GitHub
- URL: https://github.com/thelartians/revisited
- Owner: TheLartians
- Created: 2018-06-25T14:15:30.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2020-05-26T19:00:38.000Z (over 5 years ago)
- Last Synced: 2025-03-31T04:04:14.005Z (6 months ago)
- Topics: acyclic, any, anyfunction, compile-time, cplusplus, cpp, fast, function, inheritance, multimethods, multiple-dispatch, template, visitor, visitor-pattern
- Language: C++
- Homepage:
- Size: 186 KB
- Stars: 15
- Watchers: 4
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
[](https://github.com/TheLartians/Revisited/actions)
[](https://github.com/TheLartians/Revisited/actions)
[](https://github.com/TheLartians/Revisited/actions)
[](https://github.com/TheLartians/Revisited/actions)
[](https://github.com/TheLartians/Revisited/actions)
[](https://codecov.io/gh/TheLartians/Revisited)# Revisited
A C++17 acyclic visitor template and inheritance-aware any and any-function class. Using revisited::Visitor greatly reduces the boilerplate code required for implementing the [visitor pattern](https://en.wikipedia.org/wiki/Visitor_pattern) in C++. It uses only [compile time type information](https://github.com/TheLartians/StaticTypeInfo) and has better performance than solutions relying on run time type information such as `dynamic_cast`.
## Examples
See the [examples directory](https://github.com/TheLartians/Visitor/tree/master/examples) for full examples.
### Revisited Examples
#### Simple Visitor
```cpp
#include
#include
#includestruct Base: public virtual revisited::VisitableBase { };
struct A: public Base, public revisited::Visitable { };
struct B: public Base, public revisited::Visitable { };struct Visitor: public revisited::Visitor {
void visit(A &){ std::cout << "Visiting A" << std::endl; }
void visit(B &){ std::cout << "Visiting B" << std::endl; }
};int main() {
std::shared_ptr a = std::make_shared();
std::shared_ptr b = std::make_shared();
Visitor visitor;
a->accept(visitor); // -> Visiting A
b->accept(visitor); // -> Visiting B
}
```#### Derived Classes
revisited::Visitor also understands derived classes and classes with multiple visitable base classes. Virtual visitable base classes are also supported. When visiting a derived object, the first class matching the visitor is used (starting from parent classes). Multiple and virtual inheritance is fully supported.
```cpp
// C is inherited from A (both can be visited)
struct C: public revisited::DerivedVisitable { };
// D is inherited from A and B (A and B can be visited)
struct D: public revisited::JoinVisitable { };
// E is virtually inherited from A and B (E, A and B can be visited)
struct E: public revisited::DerivedVisitable> { };
```### revisited::Any Examples
#### Implicit casting
```cpp
revisited::Any v;
v = 42;
std::cout << v.get() << std::endl; // -> 42
std::cout << v.get() << std::endl; // -> 42
v = "Hello Any!";
std::cout << v.get() << std::endl; // -> Hello Any!
```#### Reference aware casting
```cpp
int x = 42;
revisited::Any a = std::reference_wrapper(x);
std::cout << a.get() << std::endl; // -> 42
std::cout << &a.get() == &x << std::endl; // -> 1
```#### Inheritance aware casting
```cpp
// inheritance aware
struct MyClassBase{ int value; };
struct MyClass: public MyClassBase{ MyClass(int value):MyClassBase{value}{ } };
revisited::Any v;
v.setWithBases(42);
std::cout << v.get().value << std::endl; // -> 42
std::cout << v.get().value << std::endl; // -> 42
```### revisited::AnyFunction Examples
```cpp
revisited::AnyFunction f;
f = [](int x, float y){ return x + y; };
std::cout << f(40,2).get() << std::endl; // -> 42
```## Installation and usage
With [CPM](https://github.com/TheLartians/CPM), revisited::Visitor can be used in a CMake project simply by adding the following to the project's `CMakeLists.txt`.
```cmake
CPMAddPackage(
NAME Revisited
GIT_REPOSITORY https://github.com/TheLartians/Visitor.git
VERSION 2.0
)target_link_libraries(myProject Revisited)
```Alternatively, the repository can be cloned locally and included it via `add_subdirectory`. Installing revisited::Visitor will make it findable in CMake's `find_package`.
## Performance
revisited::Visitor uses meta-programming to determine the inheritance hierarchy at compile-time for optimal performance. Compared to the traditional visitor pattern revisited::Visitor requires an additional virtual calls (as the type of the visitor and the visitable object are unknown). With compiler optimizations enabled, these calls should be hardly noticeable in real-world applications.
There is an benchmark suite included in the repository that compares the pure cost of the different approaches.
```bash
cmake -Hbenchmark -Bbuild/bench -DCMAKE_BUILD_TYPE=Release
cmake --build build/bench -j8
./build/bench/RevisitedBenchmark
```