From 08a1b593aa835d0c18fbcb2e5dc76e4cc2ec50fd Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Sat, 15 Aug 2015 21:20:08 +0200
Subject: [PATCH] addapt to drop visitor capablity

---
 acompare2/src/AutomatonCompare.cpp            | 120 ++++++------------
 acompare2/src/AutomatonCompare.h              |  35 +----
 acompare2/src/GrammarCompare.cpp              |  84 ++++--------
 acompare2/src/GrammarCompare.h                |  29 +----
 aconvert2/src/DotConverter.h                  |   2 +-
 aconvert2/src/GasTexConverter.h               |   2 +-
 .../src/arbology/exact/ExactSubtreeMatch.h    |   1 +
 .../exact/ExactSubtreeMatchingAutomaton.h     |   1 +
 .../src/automaton/properties/EpsilonClosure.h |   2 +-
 .../grammar/generate/GenerateUpToLength.cpp   |  74 +----------
 .../src/grammar/generate/GenerateUpToLength.h |  26 +---
 .../properties/NonterminalUnitRuleCycle.h     |   2 +-
 alib2algo/src/grammar/simplify/ToGNF.h        |   2 +-
 .../src/graph/shortestpath/BellmanFord.h      |   2 +-
 alib2algo/src/graph/shortestpath/Dijkstra.h   |   2 +-
 alib2algo/src/graph/spanningtree/JarnikPrim.h |   2 +-
 alib2algo/src/regexp/convert/ToGrammar.h      |   1 +
 .../src/regexp/transform/RegExpDerivation.h   |   2 +-
 .../src/regexp/transform/RegExpIntegral.h     |   2 +-
 alib2algo/src/string/naive/ExactCompare.h     |   1 +
 alib2algo/src/string/naive/ExactEqual.h       |   1 +
 .../src/string/simplify/NormalizeRotation.h   |   1 +
 .../exact/BadCharacterShiftTable.h            |   2 +-
 alib2data/src/common/multipleDispatch.hpp     |  30 ++---
 alib2data/test-src/common/DispatchTest.cpp    |   2 +-
 alib2raw/src/tree/TreeToRawComposer.h         |   2 +-
 .../src/alphabet/SymbolToStringComposer.h     |   2 +-
 .../src/automaton/AutomatonToStringComposer.h |   2 +-
 .../src/grammar/GrammarToStringComposer.h     |   2 +-
 alib2str/src/graph/GraphToStringComposer.h    |   2 +-
 alib2str/src/label/LabelToStringComposer.h    |   2 +-
 .../src/primitive/PrimitiveToStringComposer.h |   2 +-
 alib2str/src/regexp/RegExpToStringComposer.h  |   2 +-
 alib2str/src/string/StringToStringComposer.h  |   2 +-
 astat2/src/AutomataStat.cpp                   |  84 +-----------
 astat2/src/AutomataStat.h                     |  31 +----
 36 files changed, 145 insertions(+), 416 deletions(-)

diff --git a/acompare2/src/AutomatonCompare.cpp b/acompare2/src/AutomatonCompare.cpp
index 3a685478db..b7720a52fc 100644
--- a/acompare2/src/AutomatonCompare.cpp
+++ b/acompare2/src/AutomatonCompare.cpp
@@ -1184,6 +1184,8 @@ int AutomatonCompare::compare(const automaton::DFA& a, const automaton::DFA& b)
 	}
 }
 
+auto AutomatonCompareDFA = AutomatonCompare::RegistratorWrapper<int, automaton::DFA, automaton::DFA>(AutomatonCompare::getInstance(), AutomatonCompare::compare);
+
 int AutomatonCompare::compare(const automaton::NFA& a, const automaton::NFA& b) {
 	if(!AutomatonCompare::testCompare(a, b)) {
 	  AutomatonCompare::printCompare(a, b);
@@ -1193,6 +1195,8 @@ int AutomatonCompare::compare(const automaton::NFA& a, const automaton::NFA& b)
 	}
 }
 
+auto AutomatonCompareNFA = AutomatonCompare::RegistratorWrapper<int, automaton::NFA, automaton::NFA>(AutomatonCompare::getInstance(), AutomatonCompare::compare);
+
 int AutomatonCompare::compare(const automaton::MultiInitialStateNFA& a, const automaton::MultiInitialStateNFA& b) {
 	if(!AutomatonCompare::testCompare(a, b)) {
 	  AutomatonCompare::printCompare(a, b);
@@ -1202,6 +1206,8 @@ int AutomatonCompare::compare(const automaton::MultiInitialStateNFA& a, const au
 	}
 }
 
+auto AutomatonCompareMultiInitialStateNFA = AutomatonCompare::RegistratorWrapper<int, automaton::MultiInitialStateNFA, automaton::MultiInitialStateNFA>(AutomatonCompare::getInstance(), AutomatonCompare::compare);
+
 int AutomatonCompare::compare(const automaton::EpsilonNFA& a, const automaton::EpsilonNFA& b) {
 	if(!AutomatonCompare::testCompare(a, b)) {
 	  AutomatonCompare::printCompare(a, b);
@@ -1211,6 +1217,8 @@ int AutomatonCompare::compare(const automaton::EpsilonNFA& a, const automaton::E
 	}
 }
 
+auto AutomatonCompareEpsilonNFA = AutomatonCompare::RegistratorWrapper<int, automaton::EpsilonNFA, automaton::EpsilonNFA>(AutomatonCompare::getInstance(), AutomatonCompare::compare);
+
 int AutomatonCompare::compare(const automaton::ExtendedNFA& a, const automaton::ExtendedNFA& b) {
 	if(!AutomatonCompare::testCompare(a, b)) {
 	  AutomatonCompare::printCompare(a, b);
@@ -1220,6 +1228,8 @@ int AutomatonCompare::compare(const automaton::ExtendedNFA& a, const automaton::
 	}
 }
 
+auto AutomatonCompareExtendedNFA = AutomatonCompare::RegistratorWrapper<int, automaton::ExtendedNFA, automaton::ExtendedNFA>(AutomatonCompare::getInstance(), AutomatonCompare::compare);
+
 int AutomatonCompare::compare(const automaton::CompactNFA& a, const automaton::CompactNFA& b) {
 	if(!AutomatonCompare::testCompare(a, b)) {
 	  AutomatonCompare::printCompare(a, b);
@@ -1229,6 +1239,8 @@ int AutomatonCompare::compare(const automaton::CompactNFA& a, const automaton::C
 	}
 }
 
+auto AutomatonCompareCompactNFA = AutomatonCompare::RegistratorWrapper<int, automaton::CompactNFA, automaton::CompactNFA>(AutomatonCompare::getInstance(), AutomatonCompare::compare);
+
 int AutomatonCompare::compare(const automaton::DFTA& a, const automaton::DFTA& b) {
 	if(!AutomatonCompare::testCompare(a, b)) {
 	  AutomatonCompare::printCompare(a, b);
@@ -1238,6 +1250,8 @@ int AutomatonCompare::compare(const automaton::DFTA& a, const automaton::DFTA& b
 	}
 }
 
+auto AutomatonCompareDFTA = AutomatonCompare::RegistratorWrapper<int, automaton::DFTA, automaton::DFTA>(AutomatonCompare::getInstance(), AutomatonCompare::compare);
+
 int AutomatonCompare::compare(const automaton::NFTA& a, const automaton::NFTA& b) {
 	if(!AutomatonCompare::testCompare(a, b)) {
 	  AutomatonCompare::printCompare(a, b);
@@ -1247,6 +1261,8 @@ int AutomatonCompare::compare(const automaton::NFTA& a, const automaton::NFTA& b
 	}
 }
 
+auto AutomatonCompareNFTA = AutomatonCompare::RegistratorWrapper<int, automaton::NFTA, automaton::NFTA>(AutomatonCompare::getInstance(), AutomatonCompare::compare);
+
 int AutomatonCompare::compare(const automaton::DPDA& a, const automaton::DPDA& b) {
 	if(!AutomatonCompare::testCompare(a, b)) {
 	  AutomatonCompare::printCompare(a, b);
@@ -1256,6 +1272,8 @@ int AutomatonCompare::compare(const automaton::DPDA& a, const automaton::DPDA& b
 	}
 }
 
+auto AutomatonCompareDPDA = AutomatonCompare::RegistratorWrapper<int, automaton::DPDA, automaton::DPDA>(AutomatonCompare::getInstance(), AutomatonCompare::compare);
+
 int AutomatonCompare::compare(const automaton::NPDA& a, const automaton::NPDA& b) {
 	if(!AutomatonCompare::testCompare(a, b)) {
 	  AutomatonCompare::printCompare(a, b);
@@ -1265,6 +1283,8 @@ int AutomatonCompare::compare(const automaton::NPDA& a, const automaton::NPDA& b
 	}
 }
 
+auto AutomatonCompareNPDA = AutomatonCompare::RegistratorWrapper<int, automaton::NPDA, automaton::NPDA>(AutomatonCompare::getInstance(), AutomatonCompare::compare);
+
 int AutomatonCompare::compare(const automaton::InputDrivenDPDA& a, const automaton::InputDrivenDPDA& b) {
 	if(!AutomatonCompare::testCompare(a, b)) {
 	  AutomatonCompare::printCompare(a, b);
@@ -1274,6 +1294,8 @@ int AutomatonCompare::compare(const automaton::InputDrivenDPDA& a, const automat
 	}
 }
 
+auto AutomatonCompareInputDrivenDPDA = AutomatonCompare::RegistratorWrapper<int, automaton::InputDrivenDPDA, automaton::InputDrivenDPDA>(AutomatonCompare::getInstance(), AutomatonCompare::compare);
+
 int AutomatonCompare::compare(const automaton::InputDrivenNPDA& a, const automaton::InputDrivenNPDA& b) {
 	if(!AutomatonCompare::testCompare(a, b)) {
 	  AutomatonCompare::printCompare(a, b);
@@ -1283,6 +1305,8 @@ int AutomatonCompare::compare(const automaton::InputDrivenNPDA& a, const automat
 	}
 }
 
+auto AutomatonCompareInputDrivenNPDA = AutomatonCompare::RegistratorWrapper<int, automaton::InputDrivenNPDA, automaton::InputDrivenNPDA>(AutomatonCompare::getInstance(), AutomatonCompare::compare);
+
 int AutomatonCompare::compare(const automaton::VisiblyPushdownDPDA& a, const automaton::VisiblyPushdownDPDA& b) {
 	if(!AutomatonCompare::testCompare(a, b)) {
 	  AutomatonCompare::printCompare(a, b);
@@ -1292,6 +1316,8 @@ int AutomatonCompare::compare(const automaton::VisiblyPushdownDPDA& a, const aut
 	}
 }
 
+auto AutomatonCompareVisiblyPushdownDPDA = AutomatonCompare::RegistratorWrapper<int, automaton::VisiblyPushdownDPDA, automaton::VisiblyPushdownDPDA>(AutomatonCompare::getInstance(), AutomatonCompare::compare);
+
 int AutomatonCompare::compare(const automaton::VisiblyPushdownNPDA& a, const automaton::VisiblyPushdownNPDA& b) {
 	if(!AutomatonCompare::testCompare(a, b)) {
 	  AutomatonCompare::printCompare(a, b);
@@ -1301,6 +1327,8 @@ int AutomatonCompare::compare(const automaton::VisiblyPushdownNPDA& a, const aut
 	}
 }
 
+auto AutomatonCompareVisiblyPushdownNPDA = AutomatonCompare::RegistratorWrapper<int, automaton::VisiblyPushdownNPDA, automaton::VisiblyPushdownNPDA>(AutomatonCompare::getInstance(), AutomatonCompare::compare);
+
 int AutomatonCompare::compare(const automaton::RealTimeHeightDeterministicDPDA& a, const automaton::RealTimeHeightDeterministicDPDA& b) {
 	if(!AutomatonCompare::testCompare(a, b)) {
 	  AutomatonCompare::printCompare(a, b);
@@ -1310,6 +1338,8 @@ int AutomatonCompare::compare(const automaton::RealTimeHeightDeterministicDPDA&
 	}
 }
 
+auto AutomatonCompareRealTimeHeightDeterministicDPDA = AutomatonCompare::RegistratorWrapper<int, automaton::RealTimeHeightDeterministicDPDA, automaton::RealTimeHeightDeterministicDPDA>(AutomatonCompare::getInstance(), AutomatonCompare::compare);
+
 int AutomatonCompare::compare(const automaton::RealTimeHeightDeterministicNPDA& a, const automaton::RealTimeHeightDeterministicNPDA& b) {
 	if(!AutomatonCompare::testCompare(a, b)) {
 	  AutomatonCompare::printCompare(a, b);
@@ -1319,6 +1349,8 @@ int AutomatonCompare::compare(const automaton::RealTimeHeightDeterministicNPDA&
 	}
 }
 
+auto AutomatonCompareRealTimeHeightDeterministicNPDA = AutomatonCompare::RegistratorWrapper<int, automaton::RealTimeHeightDeterministicNPDA, automaton::RealTimeHeightDeterministicNPDA>(AutomatonCompare::getInstance(), AutomatonCompare::compare);
+
 int AutomatonCompare::compare(const automaton::SinglePopDPDA& a, const automaton::SinglePopDPDA& b) {
 	if(!AutomatonCompare::testCompare(a, b)) {
 	  AutomatonCompare::printCompare(a, b);
@@ -1328,6 +1360,8 @@ int AutomatonCompare::compare(const automaton::SinglePopDPDA& a, const automaton
 	}
 }
 
+auto AutomatonCompareSinglePopDPDA = AutomatonCompare::RegistratorWrapper<int, automaton::SinglePopDPDA, automaton::SinglePopDPDA>(AutomatonCompare::getInstance(), AutomatonCompare::compare);
+
 int AutomatonCompare::compare(const automaton::SinglePopNPDA& a, const automaton::SinglePopNPDA& b) {
 	if(!AutomatonCompare::testCompare(a, b)) {
 	  AutomatonCompare::printCompare(a, b);
@@ -1337,6 +1371,8 @@ int AutomatonCompare::compare(const automaton::SinglePopNPDA& a, const automaton
 	}
 }
 
+auto AutomatonCompareSinglePopNPDA = AutomatonCompare::RegistratorWrapper<int, automaton::SinglePopNPDA, automaton::SinglePopNPDA>(AutomatonCompare::getInstance(), AutomatonCompare::compare);
+
 int AutomatonCompare::compare(const automaton::OneTapeDTM& a, const automaton::OneTapeDTM& b) {
 	if(!AutomatonCompare::testCompare(a, b)) {
 	  AutomatonCompare::printCompare(a, b);
@@ -1346,87 +1382,9 @@ int AutomatonCompare::compare(const automaton::OneTapeDTM& a, const automaton::O
 	}
 }
 
-int AutomatonCompare::compare(const automaton::Automaton& a, const automaton::Automaton& b) {
-	int res;
-	Accept((void*) &res, a.getData(), b.getData(), AutomatonCompare::AUTOMATON_COMPARE);
-	return res;
-}
-
-void AutomatonCompare::Visit(void* data, const automaton::EpsilonNFA& first, const automaton::EpsilonNFA& second) const {
-	*((int*) data) = AutomatonCompare::compare(first, second);
-}
-
-void AutomatonCompare::Visit(void* data, const automaton::CompactNFA& first, const automaton::CompactNFA& second) const {
-	*((int*) data) = AutomatonCompare::compare(first, second);
-}
-
-void AutomatonCompare::Visit(void* data, const automaton::DFA& first, const automaton::DFA& second) const {
-	*((int*) data) = AutomatonCompare::compare(first, second);
-}
-
-void AutomatonCompare::Visit(void* data, const automaton::ExtendedNFA& first, const automaton::ExtendedNFA& second) const {
-	*((int*) data) = AutomatonCompare::compare(first, second);
-}
-
-void AutomatonCompare::Visit(void* data, const automaton::MultiInitialStateNFA& first, const automaton::MultiInitialStateNFA& second) const {
-	*((int*) data) = AutomatonCompare::compare(first, second);
-}
-
-void AutomatonCompare::Visit(void* data, const automaton::NFA& first, const automaton::NFA& second) const {
-	*((int*) data) = AutomatonCompare::compare(first, second);
-}
-
-void AutomatonCompare::Visit(void* data, const automaton::DFTA& first, const automaton::DFTA& second) const {
-	*((int*) data) = AutomatonCompare::compare(first, second);
-}
-
-void AutomatonCompare::Visit(void* data, const automaton::NFTA& first, const automaton::NFTA& second) const {
-	*((int*) data) = AutomatonCompare::compare(first, second);
-}
-
-void AutomatonCompare::Visit(void* data, const automaton::DPDA& first, const automaton::DPDA& second) const {
-	*((int*) data) = AutomatonCompare::compare(first, second);
-}
-
-void AutomatonCompare::Visit(void* data, const automaton::NPDA& first, const automaton::NPDA& second) const {
-	*((int*) data) = AutomatonCompare::compare(first, second);
-}
-
-void AutomatonCompare::Visit(void* data, const automaton::InputDrivenDPDA& first, const automaton::InputDrivenDPDA& second) const {
-	*((int*) data) = AutomatonCompare::compare(first, second);
-}
-
-void AutomatonCompare::Visit(void* data, const automaton::InputDrivenNPDA& first, const automaton::InputDrivenNPDA& second) const {
-	*((int*) data) = AutomatonCompare::compare(first, second);
-}
+auto AutomatonCompareOneTapeDTM = AutomatonCompare::RegistratorWrapper<int, automaton::OneTapeDTM, automaton::OneTapeDTM>(AutomatonCompare::getInstance(), AutomatonCompare::compare);
 
-void AutomatonCompare::Visit(void* data, const automaton::RealTimeHeightDeterministicDPDA& first, const automaton::RealTimeHeightDeterministicDPDA& second) const {
-	*((int*) data) = AutomatonCompare::compare(first, second);
-}
-
-void AutomatonCompare::Visit(void* data, const automaton::RealTimeHeightDeterministicNPDA& first, const automaton::RealTimeHeightDeterministicNPDA& second) const {
-	*((int*) data) = AutomatonCompare::compare(first, second);
-}
-
-void AutomatonCompare::Visit(void* data, const automaton::SinglePopNPDA& first, const automaton::SinglePopNPDA& second) const {
-	*((int*) data) = AutomatonCompare::compare(first, second);
-}
-
-void AutomatonCompare::Visit(void* data, const automaton::SinglePopDPDA& first, const automaton::SinglePopDPDA& second) const {
-	*((int*) data) = AutomatonCompare::compare(first, second);
-}
-
-void AutomatonCompare::Visit(void* data, const automaton::VisiblyPushdownDPDA& first, const automaton::VisiblyPushdownDPDA& second) const {
-	*((int*) data) = AutomatonCompare::compare(first, second);
-}
-
-void AutomatonCompare::Visit(void* data, const automaton::VisiblyPushdownNPDA& first, const automaton::VisiblyPushdownNPDA& second) const {
-	*((int*) data) = AutomatonCompare::compare(first, second);
-}
-
-void AutomatonCompare::Visit(void* data, const automaton::OneTapeDTM& first, const automaton::OneTapeDTM& second) const {
-	*((int*) data) = AutomatonCompare::compare(first, second);
+int AutomatonCompare::compare(const automaton::Automaton& a, const automaton::Automaton& b) {
+	return getInstance().dispatch(a.getData(), b.getData());
 }
 
-const AutomatonCompare AutomatonCompare::AUTOMATON_COMPARE;
-
diff --git a/acompare2/src/AutomatonCompare.h b/acompare2/src/AutomatonCompare.h
index eb3ac08bc1..f8d568ef03 100644
--- a/acompare2/src/AutomatonCompare.h
+++ b/acompare2/src/AutomatonCompare.h
@@ -8,18 +8,17 @@
 #ifndef AUTOMATON_COMPARE_H_
 #define AUTOMATON_COMPARE_H_
 
+#include <common/multipleDispatch.hpp>
 #include <ostream>
 
 #include <automaton/Automaton.h>
+#include <automaton/AutomatonFeatures.h>
 #include <set>
 #include <list>
 #include <map>
 #include <utility>
 
-class AutomatonCompare : public automaton::VisitableAutomatonBase::const_same_visitor_type {
-public:
-	AutomatonCompare() {}
-
+class AutomatonCompare : public std::DoubleDispatch<int, automaton::AutomatonBase, automaton::AutomatonBase> {
 private:
 	static bool testCompare(const automaton::DFA& a, const automaton::DFA& b);
 	static void printCompare(const automaton::DFA& a, const automaton::DFA& b);
@@ -82,29 +81,6 @@ private:
 	template <class T> static void listCompare(const std::list<T> a, const std::list<T> b);
 	template <class T, class R> static void mapCompare(const std::map<T, R> a, const std::map<T, R> b);
 public:
-	void Visit(void* data, const automaton::CompactNFA& first, const automaton::CompactNFA& second) const;
-	void Visit(void* data, const automaton::DFA& first, const automaton::DFA& second) const;
-	void Visit(void* data, const automaton::EpsilonNFA& first, const automaton::EpsilonNFA& second) const;
-	void Visit(void* data, const automaton::ExtendedNFA& first, const automaton::ExtendedNFA& second) const;
-	void Visit(void* data, const automaton::MultiInitialStateNFA& first, const automaton::MultiInitialStateNFA& second) const;
-	void Visit(void* data, const automaton::NFA& first, const automaton::NFA& second) const;
-
-	void Visit(void* data, const automaton::DFTA& first, const automaton::DFTA& second) const;
-	void Visit(void* data, const automaton::NFTA& first, const automaton::NFTA& second) const;
-
-	void Visit(void* data, const automaton::DPDA& first, const automaton::DPDA& second) const;
-	void Visit(void* data, const automaton::NPDA& first, const automaton::NPDA& second) const;
-	void Visit(void* data, const automaton::InputDrivenNPDA& first, const automaton::InputDrivenNPDA& second) const;
-	void Visit(void* data, const automaton::InputDrivenDPDA& first, const automaton::InputDrivenDPDA& second) const;
-	void Visit(void* data, const automaton::RealTimeHeightDeterministicDPDA& first, const automaton::RealTimeHeightDeterministicDPDA& second) const;
-	void Visit(void* data, const automaton::RealTimeHeightDeterministicNPDA& first, const automaton::RealTimeHeightDeterministicNPDA& second) const;
-	void Visit(void* data, const automaton::SinglePopNPDA& first, const automaton::SinglePopNPDA& second) const;
-	void Visit(void* data, const automaton::SinglePopDPDA& first, const automaton::SinglePopDPDA& second) const;
-	void Visit(void* data, const automaton::VisiblyPushdownDPDA& first, const automaton::VisiblyPushdownDPDA& second) const;
-	void Visit(void* data, const automaton::VisiblyPushdownNPDA& first, const automaton::VisiblyPushdownNPDA& second) const;
-
-	void Visit(void* data, const automaton::OneTapeDTM& first, const automaton::OneTapeDTM& second) const;
-
 	static int compare(const automaton::DFA& a, const automaton::DFA& b);
 	static int compare(const automaton::NFA& a, const automaton::NFA& b);
 	static int compare(const automaton::MultiInitialStateNFA& a, const automaton::MultiInitialStateNFA& b);
@@ -130,7 +106,10 @@ public:
 
 	static int compare(const automaton::Automaton& a, const automaton::Automaton& b);
 
-	static const AutomatonCompare AUTOMATON_COMPARE;
+	static AutomatonCompare& getInstance() {
+		static AutomatonCompare res;
+		return res;
+	}
 };
 
 #endif /* AUTOMATON_COMPARE_H_ */
diff --git a/acompare2/src/GrammarCompare.cpp b/acompare2/src/GrammarCompare.cpp
index d290b68b07..cc8f6d3f32 100644
--- a/acompare2/src/GrammarCompare.cpp
+++ b/acompare2/src/GrammarCompare.cpp
@@ -570,6 +570,8 @@ int GrammarCompare::compare(const grammar::LeftLG& a, const grammar::LeftLG& b)
 	}
 }
 
+auto GrammarCompareLeftLG = GrammarCompare::RegistratorWrapper<int, grammar::LeftLG, grammar::LeftLG>(GrammarCompare::getInstance(), GrammarCompare::compare);
+
 int GrammarCompare::compare(const grammar::LeftRG& a, const grammar::LeftRG& b) {
 	if(!GrammarCompare::testCompare(a, b)) {
 	  GrammarCompare::printCompare(a, b);
@@ -579,6 +581,8 @@ int GrammarCompare::compare(const grammar::LeftRG& a, const grammar::LeftRG& b)
 	}
 }
 
+auto GrammarCompareLeftRG = GrammarCompare::RegistratorWrapper<int, grammar::LeftRG, grammar::LeftRG>(GrammarCompare::getInstance(), GrammarCompare::compare);
+
 int GrammarCompare::compare(const grammar::RightLG& a, const grammar::RightLG& b) {
 	if(!GrammarCompare::testCompare(a, b)) {
 	  GrammarCompare::printCompare(a, b);
@@ -588,6 +592,8 @@ int GrammarCompare::compare(const grammar::RightLG& a, const grammar::RightLG& b
 	}
 }
 
+auto GrammarCompareRightLG = GrammarCompare::RegistratorWrapper<int, grammar::RightLG, grammar::RightLG>(GrammarCompare::getInstance(), GrammarCompare::compare);
+
 int GrammarCompare::compare(const grammar::RightRG& a, const grammar::RightRG& b) {
 	if(!GrammarCompare::testCompare(a, b)) {
 	  GrammarCompare::printCompare(a, b);
@@ -597,6 +603,8 @@ int GrammarCompare::compare(const grammar::RightRG& a, const grammar::RightRG& b
 	}
 }
 
+auto GrammarCompareRightRG = GrammarCompare::RegistratorWrapper<int, grammar::RightRG, grammar::RightRG>(GrammarCompare::getInstance(), GrammarCompare::compare);
+
 int GrammarCompare::compare(const grammar::LG& a, const grammar::LG& b) {
 	if(!GrammarCompare::testCompare(a, b)) {
 	  GrammarCompare::printCompare(a, b);
@@ -606,6 +614,8 @@ int GrammarCompare::compare(const grammar::LG& a, const grammar::LG& b) {
 	}
 }
 
+auto GrammarCompareLG = GrammarCompare::RegistratorWrapper<int, grammar::LG, grammar::LG>(GrammarCompare::getInstance(), GrammarCompare::compare);
+
 int GrammarCompare::compare(const grammar::CFG& a, const grammar::CFG& b) {
 	if(!GrammarCompare::testCompare(a, b)) {
 	  GrammarCompare::printCompare(a, b);
@@ -615,6 +625,8 @@ int GrammarCompare::compare(const grammar::CFG& a, const grammar::CFG& b) {
 	}
 }
 
+auto GrammarCompareCFG = GrammarCompare::RegistratorWrapper<int, grammar::CFG, grammar::CFG>(GrammarCompare::getInstance(), GrammarCompare::compare);
+
 int GrammarCompare::compare(const grammar::EpsilonFreeCFG& a, const grammar::EpsilonFreeCFG& b) {
 	if(!GrammarCompare::testCompare(a, b)) {
 	  GrammarCompare::printCompare(a, b);
@@ -624,6 +636,8 @@ int GrammarCompare::compare(const grammar::EpsilonFreeCFG& a, const grammar::Eps
 	}
 }
 
+auto GrammarCompareEpsilonFreeCFG = GrammarCompare::RegistratorWrapper<int, grammar::EpsilonFreeCFG, grammar::EpsilonFreeCFG>(GrammarCompare::getInstance(), GrammarCompare::compare);
+
 int GrammarCompare::compare(const grammar::CNF& a, const grammar::CNF& b) {
 	if(!GrammarCompare::testCompare(a, b)) {
 	  GrammarCompare::printCompare(a, b);
@@ -633,6 +647,8 @@ int GrammarCompare::compare(const grammar::CNF& a, const grammar::CNF& b) {
 	}
 }
 
+auto GrammarCompareCNF = GrammarCompare::RegistratorWrapper<int, grammar::CNF, grammar::CNF>(GrammarCompare::getInstance(), GrammarCompare::compare);
+
 int GrammarCompare::compare(const grammar::GNF& a, const grammar::GNF& b) {
 	if(!GrammarCompare::testCompare(a, b)) {
 	  GrammarCompare::printCompare(a, b);
@@ -642,6 +658,8 @@ int GrammarCompare::compare(const grammar::GNF& a, const grammar::GNF& b) {
 	}
 }
 
+auto GrammarCompareGNF = GrammarCompare::RegistratorWrapper<int, grammar::GNF, grammar::GNF>(GrammarCompare::getInstance(), GrammarCompare::compare);
+
 int GrammarCompare::compare(const grammar::CSG& a, const grammar::CSG& b) {
 	if(!GrammarCompare::testCompare(a, b)) {
 	  GrammarCompare::printCompare(a, b);
@@ -651,6 +669,8 @@ int GrammarCompare::compare(const grammar::CSG& a, const grammar::CSG& b) {
 	}
 }
 
+auto GrammarCompareCSG = GrammarCompare::RegistratorWrapper<int, grammar::CSG, grammar::CSG>(GrammarCompare::getInstance(), GrammarCompare::compare);
+
 int GrammarCompare::compare(const grammar::NonContractingGrammar& a, const grammar::NonContractingGrammar& b) {
 	if(!GrammarCompare::testCompare(a, b)) {
 	  GrammarCompare::printCompare(a, b);
@@ -660,6 +680,8 @@ int GrammarCompare::compare(const grammar::NonContractingGrammar& a, const gramm
 	}
 }
 
+auto GrammarCompareNonContractingGrammar = GrammarCompare::RegistratorWrapper<int, grammar::NonContractingGrammar, grammar::NonContractingGrammar>(GrammarCompare::getInstance(), GrammarCompare::compare);
+
 int GrammarCompare::compare(const grammar::ContextPreservingUnrestrictedGrammar& a, const grammar::ContextPreservingUnrestrictedGrammar& b) {
 	if(!GrammarCompare::testCompare(a, b)) {
 	  GrammarCompare::printCompare(a, b);
@@ -669,6 +691,8 @@ int GrammarCompare::compare(const grammar::ContextPreservingUnrestrictedGrammar&
 	}
 }
 
+auto GrammarCompareContextPreservingUnrestrictedGrammar = GrammarCompare::RegistratorWrapper<int, grammar::ContextPreservingUnrestrictedGrammar, grammar::ContextPreservingUnrestrictedGrammar>(GrammarCompare::getInstance(), GrammarCompare::compare);
+
 int GrammarCompare::compare(const grammar::UnrestrictedGrammar& a, const grammar::UnrestrictedGrammar& b) {
 	if(!GrammarCompare::testCompare(a, b)) {
 	  GrammarCompare::printCompare(a, b);
@@ -678,63 +702,9 @@ int GrammarCompare::compare(const grammar::UnrestrictedGrammar& a, const grammar
 	}
 }
 
-int GrammarCompare::compare(const grammar::Grammar& a, const grammar::Grammar& b) {
-	int res;
-	Accept((void*) &res, a.getData(), b.getData(), GrammarCompare::GRAMMAR_COMPARE);
-	return res;
-}
-
-void GrammarCompare::Visit(void* data, const grammar::RightRG& first, const grammar::RightRG& second) const {
-	*((int*) data) = GrammarCompare::compare(first, second);
-}
-
-void GrammarCompare::Visit(void* data, const grammar::LeftRG& first, const grammar::LeftRG& second) const {
-	*((int*) data) = GrammarCompare::compare(first, second);
-}
-
-void GrammarCompare::Visit(void* data, const grammar::RightLG& first, const grammar::RightLG& second) const {
-	*((int*) data) = GrammarCompare::compare(first, second);
-}
-
-void GrammarCompare::Visit(void* data, const grammar::LeftLG& first, const grammar::LeftLG& second) const {
-	*((int*) data) = GrammarCompare::compare(first, second);
-}
-
-void GrammarCompare::Visit(void* data, const grammar::LG& first, const grammar::LG& second) const {
-	*((int*) data) = GrammarCompare::compare(first, second);
-}
-
-void GrammarCompare::Visit(void* data, const grammar::CFG& first, const grammar::CFG& second) const {
-	*((int*) data) = GrammarCompare::compare(first, second);
-}
-
-void GrammarCompare::Visit(void* data, const grammar::EpsilonFreeCFG& first, const grammar::EpsilonFreeCFG& second) const {
-	*((int*) data) = GrammarCompare::compare(first, second);
-}
-
-void GrammarCompare::Visit(void* data, const grammar::CNF& first, const grammar::CNF& second) const {
-	*((int*) data) = GrammarCompare::compare(first, second);
-}
-
-void GrammarCompare::Visit(void* data, const grammar::GNF& first, const grammar::GNF& second) const {
-	*((int*) data) = GrammarCompare::compare(first, second);
-}
-
-void GrammarCompare::Visit(void* data, const grammar::CSG& first, const grammar::CSG& second) const {
-	*((int*) data) = GrammarCompare::compare(first, second);
-}
-
-void GrammarCompare::Visit(void* data, const grammar::NonContractingGrammar& first, const grammar::NonContractingGrammar& second) const {
-	*((int*) data) = GrammarCompare::compare(first, second);
-}
-
-void GrammarCompare::Visit(void* data, const grammar::ContextPreservingUnrestrictedGrammar& first, const grammar::ContextPreservingUnrestrictedGrammar& second) const {
-	*((int*) data) = GrammarCompare::compare(first, second);
-}
+auto GrammarCompareUnrestrictedGrammar = GrammarCompare::RegistratorWrapper<int, grammar::UnrestrictedGrammar, grammar::UnrestrictedGrammar>(GrammarCompare::getInstance(), GrammarCompare::compare);
 
-void GrammarCompare::Visit(void* data, const grammar::UnrestrictedGrammar& first, const grammar::UnrestrictedGrammar& second) const {
-	*((int*) data) = GrammarCompare::compare(first, second);
+int GrammarCompare::compare(const grammar::Grammar& a, const grammar::Grammar& b) {
+	return getInstance().dispatch(a.getData(), b.getData());
 }
 
-const GrammarCompare GrammarCompare::GRAMMAR_COMPARE;
-
diff --git a/acompare2/src/GrammarCompare.h b/acompare2/src/GrammarCompare.h
index c39fdc1657..26d523521a 100644
--- a/acompare2/src/GrammarCompare.h
+++ b/acompare2/src/GrammarCompare.h
@@ -8,18 +8,17 @@
 #ifndef GRAMMAR_COMPARE_H_
 #define GRAMMAR_COMPARE_H_
 
+#include <common/multipleDispatch.hpp>
 #include <ostream>
 
 #include <grammar/Grammar.h>
+#include <grammar/GrammarFeatures.h>
 #include <set>
 #include <list>
 #include <map>
 #include <utility>
 
-class GrammarCompare : public grammar::VisitableGrammarBase::const_same_visitor_type {
-public:
-	GrammarCompare() {}
-
+class GrammarCompare : public std::DoubleDispatch<int, grammar::GrammarBase, grammar::GrammarBase> {
 private:
 	static bool testCompare(const grammar::LeftLG& a, const grammar::LeftLG& b);
 	static void printCompare(const grammar::LeftLG& a, const grammar::LeftLG& b);
@@ -64,23 +63,6 @@ private:
 	template <class T> static void listCompare(const std::list<T> a, const std::list<T> b);
 	template <class T, class R> static void mapCompare(const std::map<T, R> a, const std::map<T, R> b);
 public:
-	void Visit(void*, const grammar::RightRG& first, const grammar::RightRG& second) const;
-	void Visit(void*, const grammar::LeftRG& first, const grammar::LeftRG& second) const;
-	void Visit(void*, const grammar::RightLG& first, const grammar::RightLG& second) const;
-	void Visit(void*, const grammar::LeftLG& first, const grammar::LeftLG& second) const;
-
-	void Visit(void*, const grammar::LG& first, const grammar::LG& second) const;
-	void Visit(void*, const grammar::CFG& first, const grammar::CFG& second) const;
-	void Visit(void*, const grammar::EpsilonFreeCFG& first, const grammar::EpsilonFreeCFG& second) const;
-	void Visit(void*, const grammar::CNF& first, const grammar::CNF& second) const;
-	void Visit(void*, const grammar::GNF& first, const grammar::GNF& second) const;
-
-	void Visit(void*, const grammar::CSG& first, const grammar::CSG& second) const;
-	void Visit(void*, const grammar::NonContractingGrammar& first, const grammar::NonContractingGrammar& second) const;
-
-	void Visit(void*, const grammar::ContextPreservingUnrestrictedGrammar& first, const grammar::ContextPreservingUnrestrictedGrammar& second) const;
-	void Visit(void*, const grammar::UnrestrictedGrammar& first, const grammar::UnrestrictedGrammar& second) const;
-
 	static int compare(const grammar::LeftLG& a, const grammar::LeftLG& b);
 	static int compare(const grammar::LeftRG& a, const grammar::LeftRG& b);
 	static int compare(const grammar::RightLG& a, const grammar::RightLG& b);
@@ -97,7 +79,10 @@ public:
 
 	static int compare(const grammar::Grammar& a, const grammar::Grammar& b);
 
-	static const GrammarCompare GRAMMAR_COMPARE;
+	static GrammarCompare& getInstance() {
+		static GrammarCompare res;
+		return res;
+	}
 };
 
 #endif /* GRAMMAR_COMPARE_H_ */
diff --git a/aconvert2/src/DotConverter.h b/aconvert2/src/DotConverter.h
index b9d4ed32b2..735fcc6bbd 100644
--- a/aconvert2/src/DotConverter.h
+++ b/aconvert2/src/DotConverter.h
@@ -17,7 +17,7 @@
 #include <map>
 #include <utility>
 
-class DotConverter : public std::SingleDispatchFirstStaticParam<void, std::ostream, automaton::AutomatonBase> {
+class DotConverter : public std::SingleDispatchFirstStaticParam<void, std::ostream&, automaton::AutomatonBase> {
 	static void transitions(const automaton::EpsilonNFA& fsm, const std::map<automaton::State, int>& states, std::ostream& out);
 	static void transitions(const automaton::MultiInitialStateNFA& fsm, const std::map<automaton::State, int>& states, std::ostream& out);
 	static void transitions(const automaton::NFA& fsm, const std::map<automaton::State, int>& states, std::ostream& out);
diff --git a/aconvert2/src/GasTexConverter.h b/aconvert2/src/GasTexConverter.h
index 9de2682c03..92962ccf5c 100644
--- a/aconvert2/src/GasTexConverter.h
+++ b/aconvert2/src/GasTexConverter.h
@@ -16,7 +16,7 @@
 #include "automaton/Automaton.h"
 #include "alphabet/Symbol.h"
 
-class GasTexConverter : public std::SingleDispatchFirstStaticParam<void, std::ostream, automaton::AutomatonBase> {
+class GasTexConverter : public std::SingleDispatchFirstStaticParam<void, std::ostream&, automaton::AutomatonBase> {
 	static void printTransitionMap( const std::map<std::pair<std::string, std::string>, std::string> transitionMap, std::ostream& out);
 	static std::string getStackSymbols(const std::vector<alphabet::Symbol>& stackSymbols);
 
diff --git a/alib2algo/src/arbology/exact/ExactSubtreeMatch.h b/alib2algo/src/arbology/exact/ExactSubtreeMatch.h
index c596fd0419..e87037a7ac 100644
--- a/alib2algo/src/arbology/exact/ExactSubtreeMatch.h
+++ b/alib2algo/src/arbology/exact/ExactSubtreeMatch.h
@@ -9,6 +9,7 @@
 #define _EXACT_SUBTREE_MATCH_H_
 
 #include <tree/Tree.h>
+#include <tree/TreeFeatures.h>
 #include <tree/ranked/RankedNode.h>
 #include <tree/unranked/UnrankedNode.h>
 #include <set>
diff --git a/alib2algo/src/arbology/exact/ExactSubtreeMatchingAutomaton.h b/alib2algo/src/arbology/exact/ExactSubtreeMatchingAutomaton.h
index 436eb92390..715e1f3cfb 100644
--- a/alib2algo/src/arbology/exact/ExactSubtreeMatchingAutomaton.h
+++ b/alib2algo/src/arbology/exact/ExactSubtreeMatchingAutomaton.h
@@ -12,6 +12,7 @@
 #include <automaton/PDA/InputDrivenNPDA.h>
 #include <automaton/TA/NFTA.h>
 #include <tree/Tree.h>
+#include <tree/TreeFeatures.h>
 #include <common/multipleDispatch.hpp>
 
 namespace arbology {
diff --git a/alib2algo/src/automaton/properties/EpsilonClosure.h b/alib2algo/src/automaton/properties/EpsilonClosure.h
index 4b156c6e93..df15acee6d 100644
--- a/alib2algo/src/automaton/properties/EpsilonClosure.h
+++ b/alib2algo/src/automaton/properties/EpsilonClosure.h
@@ -20,7 +20,7 @@ namespace automaton {
 
 namespace properties {
 
-class EpsilonClosure : public std::SingleDispatchLastStaticParam<std::set<automaton::State>, automaton::AutomatonBase, const automaton::State> {
+class EpsilonClosure : public std::SingleDispatchLastStaticParam<std::set<automaton::State>, automaton::AutomatonBase, const automaton::State&> {
 public:
 	static std::set<automaton::State> epsilonClosure( const automaton::Automaton & automaton, const automaton::State & state );
 
diff --git a/alib2algo/src/grammar/generate/GenerateUpToLength.cpp b/alib2algo/src/grammar/generate/GenerateUpToLength.cpp
index 33d7d6bdac..221495bb93 100644
--- a/alib2algo/src/grammar/generate/GenerateUpToLength.cpp
+++ b/alib2algo/src/grammar/generate/GenerateUpToLength.cpp
@@ -61,78 +61,16 @@ std::set<string::LinearString> GenerateUpToLength::generate( const T & grammar,
 	return res;
 }
 
-template std::set<string::LinearString> GenerateUpToLength::generate( const grammar::EpsilonFreeCFG & grammar, unsigned length );
-template std::set<string::LinearString> GenerateUpToLength::generate( const grammar::GNF & grammar, unsigned length );
-template std::set<string::LinearString> GenerateUpToLength::generate( const grammar::CNF & grammar, unsigned length );
-template std::set<string::LinearString> GenerateUpToLength::generate( const grammar::LeftRG & grammar, unsigned length );
-template std::set<string::LinearString> GenerateUpToLength::generate( const grammar::RightRG & grammar, unsigned length );
+auto GenerateUpToLengthEpsilonFreeCFG = GenerateUpToLength::RegistratorWrapper<std::set<string::LinearString>, grammar::EpsilonFreeCFG>(GenerateUpToLength::getInstance(), GenerateUpToLength::generate);
+auto GenerateUpToLengthGNF = GenerateUpToLength::RegistratorWrapper<std::set<string::LinearString>, grammar::GNF>(GenerateUpToLength::getInstance(), GenerateUpToLength::generate);
+auto GenerateUpToLengthCNF = GenerateUpToLength::RegistratorWrapper<std::set<string::LinearString>, grammar::CNF>(GenerateUpToLength::getInstance(), GenerateUpToLength::generate);
+auto GenerateUpToLengthLeftRG = GenerateUpToLength::RegistratorWrapper<std::set<string::LinearString>, grammar::LeftRG>(GenerateUpToLength::getInstance(), GenerateUpToLength::generate);
+auto GenerateUpToLengthRightRG = GenerateUpToLength::RegistratorWrapper<std::set<string::LinearString>, grammar::RightRG>(GenerateUpToLength::getInstance(), GenerateUpToLength::generate);
 
 std::set<string::LinearString> GenerateUpToLength::generate(const grammar::Grammar& grammar, unsigned length) {
-	std::pair<std::set<string::LinearString>, unsigned> out;
-	out.second = length;
-	grammar.getData().Accept((void*) &out, GenerateUpToLength::GENERATE_UP_TO_LENGTH);
-	return std::move(out.first);
+	return getInstance().dispatch(grammar.getData(), length);
 }
 
-void GenerateUpToLength::Visit(void*, const grammar::LeftLG&) const {
-	throw exception::AlibException("Unsupported grammar type LeftLG");
-}
-
-void GenerateUpToLength::Visit(void* data, const grammar::LeftRG& grammar) const {
-	std::pair<std::set<string::LinearString>, unsigned>& out = *((std::pair<std::set<string::LinearString>, unsigned>*) data);
-	out.first = this->generate(grammar, out.second);
-}
-
-void GenerateUpToLength::Visit(void*, const grammar::RightLG&) const {
-	throw exception::AlibException("Unsupported grammar type RightLG");
-}
-
-void GenerateUpToLength::Visit(void* data, const grammar::RightRG& grammar) const {
-	std::pair<std::set<string::LinearString>, unsigned>& out = *((std::pair<std::set<string::LinearString>, unsigned>*) data);
-	out.first = this->generate(grammar, out.second);
-}
-
-void GenerateUpToLength::Visit(void*, const grammar::LG&) const {
-	throw exception::AlibException("Unsupported grammar type LG");
-}
-
-void GenerateUpToLength::Visit(void*, const grammar::CFG&) const {
-	throw exception::AlibException("Unsupported grammar type CFG");
-}
-
-void GenerateUpToLength::Visit(void* data, const grammar::EpsilonFreeCFG& grammar) const {
-	std::pair<std::set<string::LinearString>, unsigned>& out = *((std::pair<std::set<string::LinearString>, unsigned>*) data);
-	out.first = this->generate(grammar, out.second);
-}
-
-void GenerateUpToLength::Visit(void* data, const grammar::CNF& grammar) const {
-	std::pair<std::set<string::LinearString>, unsigned>& out = *((std::pair<std::set<string::LinearString>, unsigned>*) data);
-	out.first = this->generate(grammar, out.second);
-}
-
-void GenerateUpToLength::Visit(void* data, const grammar::GNF& grammar) const {
-	std::pair<std::set<string::LinearString>, unsigned>& out = *((std::pair<std::set<string::LinearString>, unsigned>*) data);
-	out.first = this->generate(grammar, out.second);
-}
-
-void GenerateUpToLength::Visit(void*, const grammar::CSG&) const {
-	throw exception::AlibException("Unsupported grammar type CSG");
-}
-
-void GenerateUpToLength::Visit(void*, const grammar::NonContractingGrammar&) const {
-	throw exception::AlibException("Unsupported grammar type NonConctractingGrammar");
-}
-
-void GenerateUpToLength::Visit(void*, const grammar::ContextPreservingUnrestrictedGrammar&) const {
-	throw exception::AlibException("Unsupported grammar type ContextPreservingUnrestrictedGrammar");
-}
-
-void GenerateUpToLength::Visit(void*, const grammar::UnrestrictedGrammar&) const {
-	throw exception::AlibException("Unsupported grammar type UnrestrictedGrammar");
-}
-
-const GenerateUpToLength GenerateUpToLength::GENERATE_UP_TO_LENGTH;
-
 } /* namespace generate */
 
 } /* namespace grammar */
diff --git a/alib2algo/src/grammar/generate/GenerateUpToLength.h b/alib2algo/src/grammar/generate/GenerateUpToLength.h
index 26b2d1fc8b..0a1abcf8d5 100644
--- a/alib2algo/src/grammar/generate/GenerateUpToLength.h
+++ b/alib2algo/src/grammar/generate/GenerateUpToLength.h
@@ -8,6 +8,8 @@
 #ifndef GRAMMAR_GENERATE_UP_TO_LENGTH_H_
 #define GRAMMAR_GENERATE_UP_TO_LENGTH_H_
 
+#include <common/multipleDispatch.hpp>
+
 #include <grammar/Grammar.h>
 #include <string/LinearString.h>
 #include <set>
@@ -19,31 +21,17 @@ namespace generate {
 /**
  * Implements algorithms from Melichar, chapter 3.3
  */
-class GenerateUpToLength : public grammar::VisitableGrammarBase::const_visitor_type {
+class GenerateUpToLength : public std::SingleDispatchLastStaticParam<std::set<string::LinearString>, grammar::GrammarBase, unsigned> {
 public:
-	GenerateUpToLength() {}
-
 	static std::set<string::LinearString> generate( const grammar::Grammar & grammar, unsigned length );
 
 	template<class T>
 	static std::set<string::LinearString> generate( const T & grammar, unsigned length );
 
-private:
-	void Visit(void*, const grammar::LeftLG& grammar) const;
-	void Visit(void*, const grammar::LeftRG& grammar) const;
-	void Visit(void*, const grammar::RightLG& grammar) const;
-	void Visit(void*, const grammar::RightRG& grammar) const;
-	void Visit(void*, const grammar::LG& grammar) const;
-	void Visit(void*, const grammar::CFG& grammar) const;
-	void Visit(void*, const grammar::EpsilonFreeCFG& grammar) const;
-	void Visit(void*, const grammar::CNF& grammar) const;
-	void Visit(void*, const grammar::GNF& grammar) const;
-	void Visit(void*, const grammar::CSG& grammar) const;
-	void Visit(void*, const grammar::NonContractingGrammar& grammar) const;
-	void Visit(void*, const grammar::ContextPreservingUnrestrictedGrammar& grammar) const;
-	void Visit(void*, const grammar::UnrestrictedGrammar& grammar) const;
-
-	static const GenerateUpToLength GENERATE_UP_TO_LENGTH;
+	static GenerateUpToLength& getInstance() {
+		static GenerateUpToLength res;
+		return res;
+	}
 };
 
 } /* namespace generate */
diff --git a/alib2algo/src/grammar/properties/NonterminalUnitRuleCycle.h b/alib2algo/src/grammar/properties/NonterminalUnitRuleCycle.h
index 62c9206b94..9cb25fe022 100644
--- a/alib2algo/src/grammar/properties/NonterminalUnitRuleCycle.h
+++ b/alib2algo/src/grammar/properties/NonterminalUnitRuleCycle.h
@@ -20,7 +20,7 @@ namespace properties {
 /**
  * Implements algorithms from Melichar, chapter 3.3
  */
-class NonterminalUnitRuleCycle : public std::SingleDispatchLastStaticParam<std::set<alphabet::Symbol>, grammar::GrammarBase, const alphabet::Symbol> {
+class NonterminalUnitRuleCycle : public std::SingleDispatchLastStaticParam<std::set<alphabet::Symbol>, grammar::GrammarBase, const alphabet::Symbol&> {
 public:
 	static std::set<alphabet::Symbol> getNonterminalUnitRuleCycle( const grammar::Grammar & grammar, const alphabet::Symbol& nonterminal );
 
diff --git a/alib2algo/src/grammar/simplify/ToGNF.h b/alib2algo/src/grammar/simplify/ToGNF.h
index 4f9662646b..bc7ece3777 100644
--- a/alib2algo/src/grammar/simplify/ToGNF.h
+++ b/alib2algo/src/grammar/simplify/ToGNF.h
@@ -16,7 +16,7 @@
 
 #include <grammar/ContextFree/CFG.h>
 #include <grammar/ContextFree/EpsilonFreeCFG.h>
-#include <grammar/ContextFree/GNF.h>
+#include <grammar/ContextFree/CNF.h>
 #include <grammar/ContextFree/GNF.h>
 #include <grammar/ContextFree/LG.h>
 #include <grammar/Regular/LeftLG.h>
diff --git a/alib2algo/src/graph/shortestpath/BellmanFord.h b/alib2algo/src/graph/shortestpath/BellmanFord.h
index 9c5a07e2dd..f6ae2e77ae 100644
--- a/alib2algo/src/graph/shortestpath/BellmanFord.h
+++ b/alib2algo/src/graph/shortestpath/BellmanFord.h
@@ -17,7 +17,7 @@ namespace shortestpath {
 //
 // note: negative-weight undirected edge = negative-weight cycle
 
-class BellmanFord : public std::SingleDispatchLastStaticParam<std::unordered_map<Node, int>, graph::GraphBase, const Node> {
+class BellmanFord : public std::SingleDispatchLastStaticParam<std::unordered_map<Node, int>, graph::GraphBase, const Node&> {
 public:
 	typedef std::unordered_map<Node, int> Result;
 
diff --git a/alib2algo/src/graph/shortestpath/Dijkstra.h b/alib2algo/src/graph/shortestpath/Dijkstra.h
index d1fc6af8c6..46bfa79a53 100644
--- a/alib2algo/src/graph/shortestpath/Dijkstra.h
+++ b/alib2algo/src/graph/shortestpath/Dijkstra.h
@@ -14,7 +14,7 @@ namespace shortestpath {
 
 // Dijkstra only works on graphs without negative-weight edges (>= 0)
 
-class Dijkstra : public std::SingleDispatchLastStaticParam<std::unordered_map<Node, int>, graph::GraphBase, const Node> {
+class Dijkstra : public std::SingleDispatchLastStaticParam<std::unordered_map<Node, int>, graph::GraphBase, const Node&> {
 public:
 	typedef std::unordered_map<Node, int> Result;
 
diff --git a/alib2algo/src/graph/spanningtree/JarnikPrim.h b/alib2algo/src/graph/spanningtree/JarnikPrim.h
index 05d8054124..8489805fd2 100644
--- a/alib2algo/src/graph/spanningtree/JarnikPrim.h
+++ b/alib2algo/src/graph/spanningtree/JarnikPrim.h
@@ -10,7 +10,7 @@ namespace graph {
 
 namespace spanningtree {
 
-class JarnikPrim : public std::SingleDispatchLastStaticParam<graph::Graph, graph::GraphBase, const Node> {
+class JarnikPrim : public std::SingleDispatchLastStaticParam<graph::Graph, graph::GraphBase, const Node&> {
 public:
 	static Graph jarnikprim(const Graph &graph, const Node &start);
 
diff --git a/alib2algo/src/regexp/convert/ToGrammar.h b/alib2algo/src/regexp/convert/ToGrammar.h
index 6adfdcd343..7af33ebe96 100644
--- a/alib2algo/src/regexp/convert/ToGrammar.h
+++ b/alib2algo/src/regexp/convert/ToGrammar.h
@@ -12,6 +12,7 @@
 
 #include <grammar/Grammar.h>
 #include <regexp/RegExp.h>
+#include <regexp/RegExpFeatures.h>
 
 namespace regexp {
 
diff --git a/alib2algo/src/regexp/transform/RegExpDerivation.h b/alib2algo/src/regexp/transform/RegExpDerivation.h
index 5f0907b192..71ea567a20 100644
--- a/alib2algo/src/regexp/transform/RegExpDerivation.h
+++ b/alib2algo/src/regexp/transform/RegExpDerivation.h
@@ -25,7 +25,7 @@ namespace regexp {
  *  - Melichar, definition 2.91 in chapter 2.4.3
  *  - Brzozowski, J. A. - Derivatives of regular expressions (1964)
  */
-class RegExpDerivation : public std::SingleDispatchLastStaticParam<regexp::RegExp, regexp::RegExpBase, const string::LinearString>, regexp::FormalRegExpElement::const_visitor_type, regexp::UnboundedRegExpElement::const_visitor_type {
+class RegExpDerivation : public std::SingleDispatchLastStaticParam<regexp::RegExp, regexp::RegExpBase, const string::LinearString&>, regexp::FormalRegExpElement::const_visitor_type, regexp::UnboundedRegExpElement::const_visitor_type {
 public:
 	RegExpDerivation() {}
 
diff --git a/alib2algo/src/regexp/transform/RegExpIntegral.h b/alib2algo/src/regexp/transform/RegExpIntegral.h
index defdf94aea..6457207a9d 100644
--- a/alib2algo/src/regexp/transform/RegExpIntegral.h
+++ b/alib2algo/src/regexp/transform/RegExpIntegral.h
@@ -23,7 +23,7 @@ namespace regexp
  * Calculates integral of regular expression
  * Source: Melichar definition 2.93 in chapter 2.4.4
  */
-class RegExpIntegral : public std::SingleDispatchLastStaticParam<regexp::RegExp, regexp::RegExpBase, const string::LinearString>, regexp::FormalRegExpElement::const_visitor_type, regexp::UnboundedRegExpElement::const_visitor_type
+class RegExpIntegral : public std::SingleDispatchLastStaticParam<regexp::RegExp, regexp::RegExpBase, const string::LinearString&>, regexp::FormalRegExpElement::const_visitor_type, regexp::UnboundedRegExpElement::const_visitor_type
 {
 public:
 	RegExpIntegral() {}
diff --git a/alib2algo/src/string/naive/ExactCompare.h b/alib2algo/src/string/naive/ExactCompare.h
index fc4825128a..e6597d8cb1 100644
--- a/alib2algo/src/string/naive/ExactCompare.h
+++ b/alib2algo/src/string/naive/ExactCompare.h
@@ -10,6 +10,7 @@
 
 #include <common/multipleDispatch.hpp>
 #include <string/String.h>
+#include <string/StringFeatures.h>
 
 namespace string {
 
diff --git a/alib2algo/src/string/naive/ExactEqual.h b/alib2algo/src/string/naive/ExactEqual.h
index 991b94dbcf..88826e59d9 100644
--- a/alib2algo/src/string/naive/ExactEqual.h
+++ b/alib2algo/src/string/naive/ExactEqual.h
@@ -10,6 +10,7 @@
 
 #include <common/multipleDispatch.hpp>
 #include <string/String.h>
+#include <string/StringFeatures.h>
 
 namespace string {
 
diff --git a/alib2algo/src/string/simplify/NormalizeRotation.h b/alib2algo/src/string/simplify/NormalizeRotation.h
index b8c1817fb6..aaa69df69d 100644
--- a/alib2algo/src/string/simplify/NormalizeRotation.h
+++ b/alib2algo/src/string/simplify/NormalizeRotation.h
@@ -11,6 +11,7 @@
 #include <common/multipleDispatch.hpp>
 
 #include <string/String.h>
+#include <string/StringFeatures.h>
 
 namespace string {
 
diff --git a/alib2algo/src/stringology/exact/BadCharacterShiftTable.h b/alib2algo/src/stringology/exact/BadCharacterShiftTable.h
index 0fcae07f1e..b8839b7de8 100644
--- a/alib2algo/src/stringology/exact/BadCharacterShiftTable.h
+++ b/alib2algo/src/stringology/exact/BadCharacterShiftTable.h
@@ -23,7 +23,7 @@ namespace exact {
  * Computation of BCS table for BMH from MI(E+\eps)-EVY course 2014
  * To get rid of zeros in BCS table we ignore last haystack character
  */
-class BadCharacterShiftTable : public std::SingleDispatchFirstStaticParam<std::map<alphabet::Symbol, size_t>, const std::set<alphabet::Symbol>, string::StringBase> {
+class BadCharacterShiftTable : public std::SingleDispatchFirstStaticParam<std::map<alphabet::Symbol, size_t>, const std::set<alphabet::Symbol>&, string::StringBase> {
 public:
 	/**
 	 * Search for pattern in linear string.
diff --git a/alib2data/src/common/multipleDispatch.hpp b/alib2data/src/common/multipleDispatch.hpp
index 84a00a5978..5b34f5b554 100644
--- a/alib2data/src/common/multipleDispatch.hpp
+++ b/alib2data/src/common/multipleDispatch.hpp
@@ -61,7 +61,7 @@ class SingleDispatchFirstStaticParam {
 public:
 	class RegistratorWrapperBase {
 	public:
-		virtual ReturnType eval(StaticParamType&, const FirstParameterType&) = 0;
+		virtual ReturnType eval(StaticParamType, const FirstParameterType&) = 0;
 
 	};
 
@@ -73,21 +73,21 @@ private:
 public:
 	template<class RealReturnType, class RealFirstParameterType>
 	class RegistratorWrapper : public RegistratorWrapperBase {
-		std::function<RealReturnType(StaticParamType&, const RealFirstParameterType&)> callback;
+		std::function<RealReturnType(StaticParamType, const RealFirstParameterType&)> callback;
 
 	public:
-		ReturnType eval(StaticParamType& res, const FirstParameterType& first) {
+		ReturnType eval(StaticParamType res, const FirstParameterType& first) {
 			return ReturnType(callback(res, (const RealFirstParameterType&) first));
 		}
 
-		RegistratorWrapper(SelfType& pool, RealReturnType(*callback)(StaticParamType&, const RealFirstParameterType&)) : callback(callback) {
+		RegistratorWrapper(SelfType& pool, RealReturnType(*callback)(StaticParamType, const RealFirstParameterType&)) : callback(callback) {
 			int a = 0;
 			if(! pool.registeredFunctions.insert(std::make_pair(RealFirstParameterType::typeId((const RealFirstParameterType&) a), this)).second )
 				throw std::logic_error("Callback alreary registered.");
 		}
 	};
 
-	ReturnType dispatch(StaticParamType& res, const FirstParameterType& first) {
+	ReturnType dispatch(StaticParamType res, const FirstParameterType& first) {
 		typename std::map<long long, RegistratorWrapperBase*>::iterator callback = registeredFunctions.find(first.selfTypeId());
 		if(callback == registeredFunctions.end()) throw std::bad_function_call();
 		return callback->second->eval(res, first);
@@ -100,7 +100,7 @@ class SingleDispatchLastStaticParam {
 public:
 	class RegistratorWrapperBase {
 	public:
-		virtual ReturnType eval(const FirstParameterType&, StaticParamType&) = 0;
+		virtual ReturnType eval(const FirstParameterType&, StaticParamType) = 0;
 
 	};
 
@@ -112,21 +112,21 @@ private:
 public:
 	template<class RealReturnType, class RealFirstParameterType>
 	class RegistratorWrapper : public RegistratorWrapperBase {
-		std::function<RealReturnType(const RealFirstParameterType&, StaticParamType&)> callback;
+		std::function<RealReturnType(const RealFirstParameterType&, StaticParamType)> callback;
 
 	public:
-		ReturnType eval(const FirstParameterType& first, StaticParamType& res) {
+		ReturnType eval(const FirstParameterType& first, StaticParamType res) {
 			return ReturnType(callback((const RealFirstParameterType&) first, res));
 		}
 
-		RegistratorWrapper(SelfType& pool, RealReturnType(*callback)(const RealFirstParameterType&, StaticParamType&)) : callback(callback) {
+		RegistratorWrapper(SelfType& pool, RealReturnType(*callback)(const RealFirstParameterType&, StaticParamType)) : callback(callback) {
 			int a = 0;
 			if(! pool.registeredFunctions.insert(std::make_pair(RealFirstParameterType::typeId((const RealFirstParameterType&) a), this)). second)
 				throw std::logic_error("Callback alreary registered.");
 		}
 	};
 
-	ReturnType dispatch(const FirstParameterType& first, StaticParamType& res) {
+	ReturnType dispatch(const FirstParameterType& first, StaticParamType res) {
 		typename std::map<long long, RegistratorWrapperBase*>::iterator callback = registeredFunctions.find(first.selfTypeId());
 		if(callback == registeredFunctions.end()) throw std::bad_function_call();
 		return callback->second->eval(first, res);
@@ -282,7 +282,7 @@ class DoubleDispatchFirstStaticParam {
 public:
 	class RegistratorWrapperBase {
 	public:
-		virtual ReturnType eval(StaticParamType&, const FirstParameterType&, const SecondParameterType&) = 0;
+		virtual ReturnType eval(StaticParamType, const FirstParameterType&, const SecondParameterType&) = 0;
 
 	};
 
@@ -294,21 +294,21 @@ private:
 public:
 	template<class RealReturnType, class RealFirstParameterType, class RealSecondParameterType>
 	class RegistratorWrapper : public RegistratorWrapperBase {
-		std::function<RealReturnType(StaticParamType&, const RealFirstParameterType&, const RealSecondParameterType&)> callback;
+		std::function<RealReturnType(StaticParamType, const RealFirstParameterType&, const RealSecondParameterType&)> callback;
 
 	public:
-		ReturnType eval(StaticParamType& res, const FirstParameterType& first, const SecondParameterType& second) {
+		ReturnType eval(StaticParamType res, const FirstParameterType& first, const SecondParameterType& second) {
 			return ReturnType(callback(res, (const RealFirstParameterType&) first, (const SecondParameterType&) second));
 		}
 
-		RegistratorWrapper(SelfType& pool, RealReturnType(*callback)(StaticParamType&, const RealFirstParameterType&, const RealSecondParameterType&)) : callback(callback) {
+		RegistratorWrapper(SelfType& pool, RealReturnType(*callback)(StaticParamType, const RealFirstParameterType&, const RealSecondParameterType&)) : callback(callback) {
 			int a = 0;
 			if(! pool.registeredFunctions.insert(std::make_pair(std::make_pair(RealFirstParameterType::typeId((const RealFirstParameterType&) a), RealSecondParameterType::typeId((const RealSecondParameterType&) a)), this)).second )
 				throw std::logic_error("Callback alreary registered.");
 		}
 	};
 
-	ReturnType dispatch(StaticParamType& res, const FirstParameterType& first, const SecondParameterType& second) {
+	ReturnType dispatch(StaticParamType res, const FirstParameterType& first, const SecondParameterType& second) {
 		typename std::map<std::pair<long long, long long>, RegistratorWrapperBase*>::iterator callback = registeredFunctions.find(std::make_pair(first.selfTypeId(), first.selfTypeId()));
 		if(callback == registeredFunctions.end()) throw std::bad_function_call();
 		return callback->second->eval(res, first, second);
diff --git a/alib2data/test-src/common/DispatchTest.cpp b/alib2data/test-src/common/DispatchTest.cpp
index bdc0370ec4..a95d33509a 100644
--- a/alib2data/test-src/common/DispatchTest.cpp
+++ b/alib2data/test-src/common/DispatchTest.cpp
@@ -210,7 +210,7 @@ namespace dispatch {
 
 // -------------------------------------------------------------------------------------------------------------------------------------------------------
 
-class TmpVisitor2 : public std::SingleDispatchFirstStaticParam<void, int, TmpBase> {
+class TmpVisitor2 : public std::SingleDispatchFirstStaticParam<void, int&, TmpBase> {
 public:
 	static void eval(int& res, const Tmp2& first) {
 		std::cout << first << std::endl;
diff --git a/alib2raw/src/tree/TreeToRawComposer.h b/alib2raw/src/tree/TreeToRawComposer.h
index f017f79c0d..4035d69ab7 100644
--- a/alib2raw/src/tree/TreeToRawComposer.h
+++ b/alib2raw/src/tree/TreeToRawComposer.h
@@ -21,7 +21,7 @@ namespace tree {
 /**
  * This class contains methods to print XML representation of tree to the output stream.
  */
-class TreeToRawComposer : public std::SingleDispatchFirstStaticParam<void, std::deque<sax::Token>, TreeBase> {
+class TreeToRawComposer : public std::SingleDispatchFirstStaticParam<void, std::deque<sax::Token>&, TreeBase> {
 public:
 	static void compose(std::deque<sax::Token>& out, const Tree& tree);
 
diff --git a/alib2str/src/alphabet/SymbolToStringComposer.h b/alib2str/src/alphabet/SymbolToStringComposer.h
index 1c47edaefd..11b584683d 100644
--- a/alib2str/src/alphabet/SymbolToStringComposer.h
+++ b/alib2str/src/alphabet/SymbolToStringComposer.h
@@ -18,7 +18,7 @@ namespace alphabet {
 /**
  * This class contains methods to print XML representation of string to the output stream.
  */
-class SymbolToStringComposer : public std::SingleDispatchFirstStaticParam<void, std::ostream, SymbolBase> {
+class SymbolToStringComposer : public std::SingleDispatchFirstStaticParam<void, std::ostream&, SymbolBase> {
 public:
 	static void compose(std::ostream& output, const LabeledSymbol& symbol);
 	static void compose(std::ostream& output, const BlankSymbol& symbol);
diff --git a/alib2str/src/automaton/AutomatonToStringComposer.h b/alib2str/src/automaton/AutomatonToStringComposer.h
index 700a6e8f6d..9034a2dee1 100644
--- a/alib2str/src/automaton/AutomatonToStringComposer.h
+++ b/alib2str/src/automaton/AutomatonToStringComposer.h
@@ -15,7 +15,7 @@
 
 namespace automaton {
 
-class AutomatonToStringComposer : public std::SingleDispatchFirstStaticParam<void, std::ostream, AutomatonBase> {
+class AutomatonToStringComposer : public std::SingleDispatchFirstStaticParam<void, std::ostream&, AutomatonBase> {
 	static void composeTransitionsFromState(std::ostream& out, const DFA& automaton, const State& from);
 	static void composeTransitionsFromState(std::ostream& out, const NFA& automaton, const State& from);
 	static void composeTransitionsFromState(std::ostream& out, const MultiInitialStateNFA& automaton, const State& from);
diff --git a/alib2str/src/grammar/GrammarToStringComposer.h b/alib2str/src/grammar/GrammarToStringComposer.h
index 495e9da237..877ad50e4d 100644
--- a/alib2str/src/grammar/GrammarToStringComposer.h
+++ b/alib2str/src/grammar/GrammarToStringComposer.h
@@ -8,7 +8,7 @@
 
 namespace grammar {
 
-class GrammarToStringComposer: public std::SingleDispatchFirstStaticParam<void, std::ostream, GrammarBase> {
+class GrammarToStringComposer: public std::SingleDispatchFirstStaticParam<void, std::ostream&, GrammarBase> {
 public:
 	template<class T>
 	static void composeCFLikeGrammar(std::ostream& output, const T& grammar);
diff --git a/alib2str/src/graph/GraphToStringComposer.h b/alib2str/src/graph/GraphToStringComposer.h
index 91405eec92..b8ea85303a 100644
--- a/alib2str/src/graph/GraphToStringComposer.h
+++ b/alib2str/src/graph/GraphToStringComposer.h
@@ -19,7 +19,7 @@
 
 namespace graph {
 
-class GraphToStringComposer : public std::SingleDispatchFirstStaticParam<void, std::ostream, GraphBase> {
+class GraphToStringComposer : public std::SingleDispatchFirstStaticParam<void, std::ostream&, GraphBase> {
 private:
 	static void composeNode(std::ostream& out, const Node &node);
 	static void composeEdge(std::ostream& out, const DirectedEdge &edge);
diff --git a/alib2str/src/label/LabelToStringComposer.h b/alib2str/src/label/LabelToStringComposer.h
index 8b88feb659..b85b6048f8 100644
--- a/alib2str/src/label/LabelToStringComposer.h
+++ b/alib2str/src/label/LabelToStringComposer.h
@@ -18,7 +18,7 @@ namespace label {
 /**
  * This class contains methods to print XML representation of string to the output stream.
  */
-class LabelToStringComposer : public std::SingleDispatchFirstStaticParam<void, std::ostream, LabelBase> {
+class LabelToStringComposer : public std::SingleDispatchFirstStaticParam<void, std::ostream&, LabelBase> {
 public:
 	static void compose(std::ostream&, const PrimitiveLabel& label);
 	static void compose(std::ostream&, const HexavigesimalLabel& label);
diff --git a/alib2str/src/primitive/PrimitiveToStringComposer.h b/alib2str/src/primitive/PrimitiveToStringComposer.h
index da37f1db94..15a7ed353b 100644
--- a/alib2str/src/primitive/PrimitiveToStringComposer.h
+++ b/alib2str/src/primitive/PrimitiveToStringComposer.h
@@ -18,7 +18,7 @@ namespace primitive {
 /**
  * This class contains methods to print XML representation of string to the output stream.
  */
-class PrimitiveToStringComposer : public std::SingleDispatchFirstStaticParam<void, std::ostream, PrimitiveBase> {
+class PrimitiveToStringComposer : public std::SingleDispatchFirstStaticParam<void, std::ostream&, PrimitiveBase> {
 public:
 	static void compose(std::ostream&, const Integer& primitive);
 	static void compose(std::ostream&, const String& primitive);
diff --git a/alib2str/src/regexp/RegExpToStringComposer.h b/alib2str/src/regexp/RegExpToStringComposer.h
index 683d2ff607..92da2f7428 100644
--- a/alib2str/src/regexp/RegExpToStringComposer.h
+++ b/alib2str/src/regexp/RegExpToStringComposer.h
@@ -16,7 +16,7 @@
 
 namespace regexp {
 
-class RegExpToStringComposer : public std::SingleDispatchFirstStaticParam<void, std::ostream, RegExpBase>, UnboundedRegExpElement::const_visitor_type, FormalRegExpElement::const_visitor_type {
+class RegExpToStringComposer : public std::SingleDispatchFirstStaticParam<void, std::ostream&, RegExpBase>, UnboundedRegExpElement::const_visitor_type, FormalRegExpElement::const_visitor_type {
 private:
 	void Visit(void*, const UnboundedRegExpAlternation& alternation) const;
 	void Visit(void*, const UnboundedRegExpConcatenation& concatenation) const;
diff --git a/alib2str/src/string/StringToStringComposer.h b/alib2str/src/string/StringToStringComposer.h
index 7119954e8e..aef54dd026 100644
--- a/alib2str/src/string/StringToStringComposer.h
+++ b/alib2str/src/string/StringToStringComposer.h
@@ -18,7 +18,7 @@ namespace string {
 /**
  * This class contains methods to print XML representation of string to the output stream.
  */
-class StringToStringComposer: public std::SingleDispatchFirstStaticParam<void, std::ostream, StringBase> {
+class StringToStringComposer: public std::SingleDispatchFirstStaticParam<void, std::ostream&, StringBase> {
 public:
 	static void compose(std::ostream&, const LinearString& string);
 	static void compose(std::ostream&, const CyclicString& string);
diff --git a/astat2/src/AutomataStat.cpp b/astat2/src/AutomataStat.cpp
index 3fc714af9e..436c6ceb81 100644
--- a/astat2/src/AutomataStat.cpp
+++ b/astat2/src/AutomataStat.cpp
@@ -18,7 +18,7 @@
 #include <iostream>
 
 void AutomataStat::stat(const automaton::Automaton& automaton, const AutomataSettings& settings) {
-	automaton.getData().Accept((void*) &settings, AutomataStat::AUTOMATA_STAT);
+	getInstance().dispatch(automaton.getData(), settings);
 }
 
 void AutomataStat::stat(const automaton::NFA& automaton, const AutomataSettings& settings) {
@@ -98,6 +98,8 @@ void AutomataStat::stat(const automaton::NFA& automaton, const AutomataSettings&
 	}
 }
 
+auto AutomataStatNFA = AutomataStat::RegistratorWrapper<void, automaton::NFA>(AutomataStat::getInstance(), AutomataStat::stat);
+
 void AutomataStat::stat(const automaton::DFA& automaton, const AutomataSettings& settings) {
 	switch(settings.states) {
 	case PrintingOptions::PRINT:
@@ -175,83 +177,5 @@ void AutomataStat::stat(const automaton::DFA& automaton, const AutomataSettings&
 	}
 }
 
-void AutomataStat::Visit(void*, const automaton::EpsilonNFA&) const {
-	throw exception::AlibException("Unsupported automaton type EpsilonNFA");
-}
-
-void AutomataStat::Visit(void*, const automaton::MultiInitialStateNFA&) const {
-	throw exception::AlibException("Unsupported automaton type EpsilonNFA");
-}
-
-void AutomataStat::Visit(void* data, const automaton::NFA& automaton) const {
-	const AutomataSettings& in = *((const AutomataSettings*) data);
-	this->stat(automaton, in);
-}
-
-void AutomataStat::Visit(void* data, const automaton::DFA& automaton) const {
-	const AutomataSettings& in = *((const AutomataSettings*) data);
-	this->stat(automaton, in);
-}
-
-void AutomataStat::Visit(void*, const automaton::ExtendedNFA&) const {
-	throw exception::AlibException("Unsupported automaton type ExtendedNFA");
-}
-
-void AutomataStat::Visit(void*, const automaton::CompactNFA&) const {
-	throw exception::AlibException("Unsupported automaton type CompactNFA");
-}
-
-void AutomataStat::Visit(void*, const automaton::DPDA&) const {
-	throw exception::AlibException("Unsupported automaton type DPDAAutomaton");
-}
-
-void AutomataStat::Visit(void*, const automaton::SinglePopDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
-}
-
-void AutomataStat::Visit(void*, const automaton::InputDrivenDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenDPDA");
-}
-
-void AutomataStat::Visit(void*, const automaton::InputDrivenNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
-}
-
-void AutomataStat::Visit(void*, const automaton::VisiblyPushdownDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
-}
-
-void AutomataStat::Visit(void*, const automaton::VisiblyPushdownNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
-}
-
-void AutomataStat::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA");
-}
-
-void AutomataStat::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA");
-}
-
-void AutomataStat::Visit(void*, const automaton::NPDA&) const {
-	throw exception::AlibException("Unsupported automaton type NPDA");
-}
-
-void AutomataStat::Visit(void*, const automaton::SinglePopNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
-}
-
-void AutomataStat::Visit(void*, const automaton::OneTapeDTM&) const {
-	throw exception::AlibException("Unsupported automaton type OneTapeDTM");
-}
-
-void AutomataStat::Visit(void*, const automaton::DFTA&) const {
-	throw exception::AlibException("Unsupported automaton type DFTA");
-}
-
-void AutomataStat::Visit(void*, const automaton::NFTA&) const {
-	throw exception::AlibException("Unsupported automaton type NFTA");
-}
-
-const AutomataStat AutomataStat::AUTOMATA_STAT;
+auto AutomataStatDFA = AutomataStat::RegistratorWrapper<void, automaton::DFA>(AutomataStat::getInstance(), AutomataStat::stat);
 
diff --git a/astat2/src/AutomataStat.h b/astat2/src/AutomataStat.h
index d3531ab855..f8fa347612 100644
--- a/astat2/src/AutomataStat.h
+++ b/astat2/src/AutomataStat.h
@@ -8,6 +8,7 @@
 #ifndef AUTOMATA_STAT_H_
 #define AUTOMATA_STAT_H_
 
+#include <common/multipleDispatch.hpp>
 #include <algorithm>
 #include <deque>
 #include <set>
@@ -17,37 +18,17 @@
 
 #include "AutomataSettings.h"
 
-class AutomataStat : public automaton::VisitableAutomatonBase::const_visitor_type {
+class AutomataStat : public std::SingleDispatchLastStaticParam<void, automaton::AutomatonBase, const AutomataSettings&> {
 public:
-	AutomataStat() {}
-
 	static void stat(const automaton::Automaton& automaton, const AutomataSettings& settings);
 
 	static void stat(const automaton::NFA& automaton, const AutomataSettings& settings);
 	static void stat(const automaton::DFA& automaton, const AutomataSettings& settings);
 
-private:
-	void Visit(void*, const automaton::EpsilonNFA& automaton) const;
-	void Visit(void*, const automaton::MultiInitialStateNFA& automaton) const;
-	void Visit(void*, const automaton::NFA& automaton) const;
-	void Visit(void*, const automaton::DFA& automaton) const;
-	void Visit(void*, const automaton::ExtendedNFA& automaton) const;
-	void Visit(void*, const automaton::CompactNFA& automaton) const;
-	void Visit(void*, const automaton::DPDA& automaton) const;
-	void Visit(void*, const automaton::SinglePopDPDA& automaton) const;
-	void Visit(void*, const automaton::InputDrivenDPDA& automaton) const;
-	void Visit(void*, const automaton::InputDrivenNPDA& automaton) const;
-	void Visit(void*, const automaton::VisiblyPushdownDPDA& automaton) const;
-	void Visit(void*, const automaton::VisiblyPushdownNPDA& automaton) const;
-	void Visit(void*, const automaton::RealTimeHeightDeterministicDPDA& automaton) const;
-	void Visit(void*, const automaton::RealTimeHeightDeterministicNPDA& automaton) const;
-	void Visit(void*, const automaton::NPDA& automaton) const;
-	void Visit(void*, const automaton::SinglePopNPDA& automaton) const;
-	void Visit(void*, const automaton::OneTapeDTM& automaton) const;
-	void Visit(void*, const automaton::NFTA& automaton) const;
-	void Visit(void*, const automaton::DFTA& automaton) const;
-
-	static const AutomataStat AUTOMATA_STAT;
+	static AutomataStat& getInstance() {
+		static AutomataStat res;
+		return res;
+	}
 };
 
 #endif /* AUTOMATA_STAT_H_ */
-- 
GitLab