diff --git a/alib2algo/src/automaton/transform/AutomataConcatenation.cpp b/alib2algo/src/automaton/transform/AutomataConcatenation.cpp
index fc3bbd95b4295cb138c0d297d7a827f29b73553d..24f13932efed09ca32a266f903fa27d057099808 100644
--- a/alib2algo/src/automaton/transform/AutomataConcatenation.cpp
+++ b/alib2algo/src/automaton/transform/AutomataConcatenation.cpp
@@ -13,23 +13,15 @@
 #define AUTOMATON_FIRST  (label::labelFrom(1))
 #define AUTOMATON_SECOND (label::labelFrom(2))
 
-namespace automaton
-{
-
-namespace transform
-{
-
-automaton::Automaton AutomataConcatenation::concatenation(const automaton::Automaton& first, const automaton::Automaton& second)
-{
-	AutomatonBase* out;
-	Accept((void*) &out, first.getData(), second.getData(), AutomataConcatenation::AUTOMATA_CONCATENATION);
-	automaton::Automaton res(*out);
-	delete out;
-	return res;
+namespace automaton {
+
+namespace transform {
+
+automaton::Automaton AutomataConcatenation::concatenation(const automaton::Automaton& first, const automaton::Automaton& second) {
+	return getInstance().dispatch(first.getData(), second.getData());
 }
 
-automaton::NFA AutomataConcatenation::concatenation(const automaton::NFA& first, const automaton::NFA& second)
-{
+automaton::NFA AutomataConcatenation::concatenation(const automaton::NFA& first, const automaton::NFA& second) {
 	automaton::State q01q02(pairLabel(first.getInitialState(), second.getInitialState()));
 	automaton::NFA res(pairLabel(AUTOMATON_FIRST, first.getInitialState()));
 
@@ -47,10 +39,8 @@ automaton::NFA AutomataConcatenation::concatenation(const automaton::NFA& first,
 	if(first.getFinalStates().count(first.getInitialState()) > 0)
 		res.setInitialState(q01q02);
 
-	for(const auto& t : first.getTransitions())
-	{
-		for(const auto& q : t.second)
-		{
+	for(const auto& t : first.getTransitions()) {
+		for(const auto& q : t.second) {
 			res.addTransition(pairLabel(AUTOMATON_FIRST, t.first.first), t.first.second, pairLabel(AUTOMATON_FIRST, q));
 
 			if(first.getFinalStates().count(q) > 0)
@@ -76,8 +66,9 @@ automaton::NFA AutomataConcatenation::concatenation(const automaton::NFA& first,
 	return res;
 }
 
-automaton::NFA AutomataConcatenation::concatenation(const automaton::DFA& first, const automaton::DFA& second)
-{
+auto AutomataConcatenationNFA = AutomataConcatenation::RegistratorWrapper<automaton::NFA, automaton::NFA>(AutomataConcatenation::getInstance(), AutomataConcatenation::concatenation);
+
+automaton::NFA AutomataConcatenation::concatenation(const automaton::DFA& first, const automaton::DFA& second) {
 	automaton::State q01q02(pairLabel(first.getInitialState(), second.getInitialState()));
 	automaton::NFA res(pairLabel(AUTOMATON_FIRST, first.getInitialState()));
 
@@ -95,8 +86,7 @@ automaton::NFA AutomataConcatenation::concatenation(const automaton::DFA& first,
 	if(first.getFinalStates().count(first.getInitialState()) > 0)
 		res.setInitialState(q01q02);
 
-	for(const auto& t : first.getTransitions())
-	{
+	for(const auto& t : first.getTransitions()) {
 		res.addTransition(pairLabel(AUTOMATON_FIRST, t.first.first), t.first.second, pairLabel(AUTOMATON_FIRST, t.second));
 
 		if(first.getFinalStates().count(t.second) > 0)
@@ -118,104 +108,7 @@ automaton::NFA AutomataConcatenation::concatenation(const automaton::DFA& first,
 	return res;
 }
 
-void AutomataConcatenation::Visit(void*, const automaton::EpsilonNFA&, const automaton::EpsilonNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type EpsilonNFA");
-}
-
-void AutomataConcatenation::Visit(void*, const automaton::CompactNFA&, const automaton::CompactNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type CompactNFA");
-}
-
-void AutomataConcatenation::Visit(void* data, const automaton::DFA& first, const automaton::DFA& second) const
-{
-	AutomatonBase* &ret = *(AutomatonBase**) data;
-	ret = std::move(AutomataConcatenation::concatenation(first, second)).plunder();
-}
-
-void AutomataConcatenation::Visit(void*, const automaton::ExtendedNFA&, const automaton::ExtendedNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type ExtendedNFA");
-}
-
-void AutomataConcatenation::Visit(void*, const automaton::MultiInitialStateNFA&, const automaton::MultiInitialStateNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type MultiInitialStateNFA");
-}
-
-void AutomataConcatenation::Visit(void* data, const automaton::NFA& first, const automaton::NFA& second) const
-{
-	AutomatonBase* &ret = *(AutomatonBase**) data;
-	ret = std::move(AutomataConcatenation::concatenation(first, second)).plunder();
-}
-
-void AutomataConcatenation::Visit(void*, const automaton::DPDA&, const automaton::DPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type DPDA");
-}
-
-void AutomataConcatenation::Visit(void*, const automaton::NPDA&, const automaton::NPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type NPDA");
-}
-
-void AutomataConcatenation::Visit(void*, const automaton::InputDrivenDPDA&, const automaton::InputDrivenDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type InputDrivenDPDA");
-}
-
-void AutomataConcatenation::Visit(void*, const automaton::InputDrivenNPDA&, const automaton::InputDrivenNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
-}
-
-void AutomataConcatenation::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&, const automaton::RealTimeHeightDeterministicDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA");
-}
-
-void AutomataConcatenation::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&, const automaton::RealTimeHeightDeterministicNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA");
-}
-
-void AutomataConcatenation::Visit(void*, const automaton::SinglePopNPDA&, const automaton::SinglePopNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
-}
-
-void AutomataConcatenation::Visit(void*, const automaton::SinglePopDPDA&, const automaton::SinglePopDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
-}
-
-void AutomataConcatenation::Visit(void*, const automaton::VisiblyPushdownDPDA&, const automaton::VisiblyPushdownDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
-}
-
-void AutomataConcatenation::Visit(void*, const automaton::VisiblyPushdownNPDA&, const automaton::VisiblyPushdownNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
-}
-
-void AutomataConcatenation::Visit(void*, const automaton::OneTapeDTM&, const automaton::OneTapeDTM&) const
-{
-	throw exception::AlibException("Unsupported automaton type OneTapeDTM");
-}
-
-void AutomataConcatenation::Visit(void*, const automaton::DFTA&, const automaton::DFTA&) const
-{
-	throw exception::AlibException("Unsupported automaton type DFTA");
-}
-
-void AutomataConcatenation::Visit(void*, const automaton::NFTA&, const automaton::NFTA&) const
-{
-	throw exception::AlibException("Unsupported automaton type NFTA");
-}
-
-const AutomataConcatenation AutomataConcatenation::AUTOMATA_CONCATENATION;
+auto AutomataConcatenationDFA = AutomataConcatenation::RegistratorWrapper<automaton::NFA, automaton::DFA>(AutomataConcatenation::getInstance(), AutomataConcatenation::concatenation);
 
 } /* namespace transform */
 
diff --git a/alib2algo/src/automaton/transform/AutomataConcatenation.h b/alib2algo/src/automaton/transform/AutomataConcatenation.h
index dc1dd54b3f2106e8d26637b5c88bb2b46e41a996..f57148bf81bd99248df0f1636524a18ec78af4b8 100644
--- a/alib2algo/src/automaton/transform/AutomataConcatenation.h
+++ b/alib2algo/src/automaton/transform/AutomataConcatenation.h
@@ -8,54 +8,29 @@
 #ifndef AUTOMATA_CONCATENATION_H_
 #define AUTOMATA_CONCATENATION_H_
 
+#include <common/multipleDispatch.hpp>
 #include <automaton/Automaton.h>
 #include <automaton/FSM/EpsilonNFA.h>
 
-namespace automaton
-{
+namespace automaton {
 
-namespace transform
-{
+namespace transform {
 
 /**
  * Concatenates two automata.
  *  - For finite automata A1, A2, we create automaton L accepting L(A1).L(A2) (Melichar, 2.78)
  */
-class AutomataConcatenation : public automaton::VisitableAutomatonBase::const_promoting_visitor_type
-{
+class AutomataConcatenation : public std::PromotingDoubleDispatch<automaton::Automaton, automaton::AutomatonBase> {
 public:
-	AutomataConcatenation() {}
-
 	static automaton::Automaton concatenation(const automaton::Automaton& first, const automaton::Automaton& second);
 
 	static automaton::NFA concatenation(const automaton::DFA& first, const automaton::DFA& second);
 	static automaton::NFA concatenation(const automaton::NFA& first, const automaton::NFA& second);
 
-private:
-	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::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;
-
-	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;
-
-	static const AutomataConcatenation AUTOMATA_CONCATENATION;
+	static AutomataConcatenation& getInstance() {
+		static AutomataConcatenation res;
+		return res;
+	}
 };
 
 } /* namespace transform */
diff --git a/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.cpp b/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.cpp
index 2c41b90c9879d1f263bccd2867f673e967777e19..f555ad7cf1df50d3024746bbdcf7753417184580 100644
--- a/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.cpp
+++ b/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.cpp
@@ -13,23 +13,15 @@
 #define AUTOMATON_FIRST  1
 #define AUTOMATON_SECOND 2
 
-namespace automaton
-{
-
-namespace transform
-{
-
-automaton::Automaton AutomataConcatenationEpsilonTransition::concatenation(const automaton::Automaton& first, const automaton::Automaton& second)
-{
-	AutomatonBase* out;
-	Accept((void*) &out, first.getData(), second.getData(), AutomataConcatenationEpsilonTransition::AUTOMATA_CONCATENATION_EPSILON_TRANSITION);
-	automaton::Automaton res(*out);
-	delete out;
-	return res;
+namespace automaton {
+
+namespace transform {
+
+automaton::Automaton AutomataConcatenationEpsilonTransition::concatenation(const automaton::Automaton& first, const automaton::Automaton& second) {
+	return getInstance().dispatch(first.getData(), second.getData());
 }
 
-automaton::EpsilonNFA AutomataConcatenationEpsilonTransition::concatenation(const automaton::DFA& first, const automaton::DFA& second)
-{
+automaton::EpsilonNFA AutomataConcatenationEpsilonTransition::concatenation(const automaton::DFA& first, const automaton::DFA& second) {
 	automaton::EpsilonNFA res(pairLabel(label::labelFrom(AUTOMATON_FIRST), first.getInitialState()));
 
 	for(const auto& symbol : first.getInputAlphabet())
@@ -57,8 +49,9 @@ automaton::EpsilonNFA AutomataConcatenationEpsilonTransition::concatenation(cons
 	return res;
 }
 
-automaton::EpsilonNFA AutomataConcatenationEpsilonTransition::concatenation(const automaton::NFA& first, const automaton::NFA& second)
-{
+auto AutomataConcatenationEpsilonTransitionDFA = AutomataConcatenationEpsilonTransition::RegistratorWrapper<automaton::EpsilonNFA, automaton::DFA>(AutomataConcatenationEpsilonTransition::getInstance(), AutomataConcatenationEpsilonTransition::concatenation);
+
+automaton::EpsilonNFA AutomataConcatenationEpsilonTransition::concatenation(const automaton::NFA& first, const automaton::NFA& second) {
 	automaton::EpsilonNFA res(pairLabel(label::labelFrom(AUTOMATON_FIRST), first.getInitialState()));
 
 	for(const auto& symbol : first.getInputAlphabet())
@@ -88,8 +81,9 @@ automaton::EpsilonNFA AutomataConcatenationEpsilonTransition::concatenation(cons
 	return res;
 }
 
-automaton::EpsilonNFA AutomataConcatenationEpsilonTransition::concatenation(const automaton::EpsilonNFA& first, const automaton::EpsilonNFA& second)
-{
+auto AutomataConcatenationEpsilonTransitionNFA = AutomataConcatenationEpsilonTransition::RegistratorWrapper<automaton::EpsilonNFA, automaton::NFA>(AutomataConcatenationEpsilonTransition::getInstance(), AutomataConcatenationEpsilonTransition::concatenation);
+
+automaton::EpsilonNFA AutomataConcatenationEpsilonTransition::concatenation(const automaton::EpsilonNFA& first, const automaton::EpsilonNFA& second) {
 	automaton::EpsilonNFA res(pairLabel(label::labelFrom(AUTOMATON_FIRST), first.getInitialState()));
 
 	for(const auto& symbol : first.getInputAlphabet())
@@ -119,105 +113,7 @@ automaton::EpsilonNFA AutomataConcatenationEpsilonTransition::concatenation(cons
 	return res;
 }
 
-void AutomataConcatenationEpsilonTransition::Visit(void* data, const automaton::EpsilonNFA& first, const automaton::EpsilonNFA& second) const
-{
-	AutomatonBase* &ret = *(AutomatonBase**) data;
-	ret = std::move(AutomataConcatenationEpsilonTransition::concatenation(first, second)).plunder();
-}
-
-void AutomataConcatenationEpsilonTransition::Visit(void*, const automaton::CompactNFA&, const automaton::CompactNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type CompactNFA");
-}
-
-void AutomataConcatenationEpsilonTransition::Visit(void* data, const automaton::DFA& first, const automaton::DFA& second) const
-{
-	AutomatonBase* &ret = *(AutomatonBase**) data;
-	ret = std::move(AutomataConcatenationEpsilonTransition::concatenation(first, second)).plunder();
-}
-
-void AutomataConcatenationEpsilonTransition::Visit(void*, const automaton::ExtendedNFA&, const automaton::ExtendedNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type ExtendedNFA");
-}
-
-void AutomataConcatenationEpsilonTransition::Visit(void*, const automaton::MultiInitialStateNFA&, const automaton::MultiInitialStateNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type MultiInitialStateNFA");
-}
-
-void AutomataConcatenationEpsilonTransition::Visit(void* data, const automaton::NFA& first, const automaton::NFA& second) const
-{
-	AutomatonBase* &ret = *(AutomatonBase**) data;
-	ret = std::move(AutomataConcatenationEpsilonTransition::concatenation(first, second)).plunder();
-}
-
-void AutomataConcatenationEpsilonTransition::Visit(void*, const automaton::DPDA&, const automaton::DPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type DPDA");
-}
-
-void AutomataConcatenationEpsilonTransition::Visit(void*, const automaton::NPDA&, const automaton::NPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type NPDA");
-}
-
-void AutomataConcatenationEpsilonTransition::Visit(void*, const automaton::InputDrivenDPDA&, const automaton::InputDrivenDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type InputDrivenDPDA");
-}
-
-void AutomataConcatenationEpsilonTransition::Visit(void*, const automaton::InputDrivenNPDA&, const automaton::InputDrivenNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
-}
-
-void AutomataConcatenationEpsilonTransition::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&, const automaton::RealTimeHeightDeterministicDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA");
-}
-
-void AutomataConcatenationEpsilonTransition::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&, const automaton::RealTimeHeightDeterministicNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA");
-}
-
-void AutomataConcatenationEpsilonTransition::Visit(void*, const automaton::SinglePopNPDA&, const automaton::SinglePopNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
-}
-
-void AutomataConcatenationEpsilonTransition::Visit(void*, const automaton::SinglePopDPDA&, const automaton::SinglePopDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
-}
-
-void AutomataConcatenationEpsilonTransition::Visit(void*, const automaton::VisiblyPushdownDPDA&, const automaton::VisiblyPushdownDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
-}
-
-void AutomataConcatenationEpsilonTransition::Visit(void*, const automaton::VisiblyPushdownNPDA&, const automaton::VisiblyPushdownNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
-}
-
-void AutomataConcatenationEpsilonTransition::Visit(void*, const automaton::OneTapeDTM&, const automaton::OneTapeDTM&) const
-{
-	throw exception::AlibException("Unsupported automaton type OneTapeDTM");
-}
-
-void AutomataConcatenationEpsilonTransition::Visit(void*, const automaton::DFTA&, const automaton::DFTA&) const
-{
-	throw exception::AlibException("Unsupported automaton type DFTA");
-}
-
-void AutomataConcatenationEpsilonTransition::Visit(void*, const automaton::NFTA&, const automaton::NFTA&) const
-{
-	throw exception::AlibException("Unsupported automaton type NFTA");
-}
-
-const AutomataConcatenationEpsilonTransition AutomataConcatenationEpsilonTransition::AUTOMATA_CONCATENATION_EPSILON_TRANSITION;
+auto AutomataConcatenationEpsilonTransitionEpsilonNFA = AutomataConcatenationEpsilonTransition::RegistratorWrapper<automaton::EpsilonNFA, automaton::EpsilonNFA>(AutomataConcatenationEpsilonTransition::getInstance(), AutomataConcatenationEpsilonTransition::concatenation);
 
 } /* namespace transform */
 
diff --git a/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.h b/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.h
index e8b27489db606020dd0a82e3881a3d0a89909063..b8e4ad8fae0fdb879c453daadd05e9877f21f56b 100644
--- a/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.h
+++ b/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.h
@@ -8,55 +8,30 @@
 #ifndef AUTOMATA_CONCATENATION_EPSILON_TRANSITION_H_
 #define AUTOMATA_CONCATENATION_EPSILON_TRANSITION_H_
 
+#include <common/multipleDispatch.hpp>
 #include <automaton/Automaton.h>
 #include <automaton/FSM/EpsilonNFA.h>
 
-namespace automaton
-{
+namespace automaton {
 
-namespace transform
-{
+namespace transform {
 
 /**
  * Concatenates two automata.
  *  - For finite automata A1, A2, we create automaton L accepting L(A1).L(A2)
  */
-class AutomataConcatenationEpsilonTransition : public automaton::VisitableAutomatonBase::const_promoting_visitor_type
-{
+class AutomataConcatenationEpsilonTransition : public std::PromotingDoubleDispatch<automaton::Automaton, automaton::AutomatonBase> {
 public:
-	AutomataConcatenationEpsilonTransition() {}
-
 	static automaton::Automaton concatenation(const automaton::Automaton& first, const automaton::Automaton& second);
 
 	static automaton::EpsilonNFA concatenation(const automaton::DFA& first, const automaton::DFA& second);
 	static automaton::EpsilonNFA concatenation(const automaton::NFA& first, const automaton::NFA& second);
 	static automaton::EpsilonNFA concatenation(const automaton::EpsilonNFA& first, const automaton::EpsilonNFA& second);
 
-private:
-	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::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::InputDrivenDPDA& first, const automaton::InputDrivenDPDA& second) const;
-	void Visit(void* data, const automaton::InputDrivenNPDA& first, const automaton::InputDrivenNPDA& 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;
-
-	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;
-
-	static const AutomataConcatenationEpsilonTransition AUTOMATA_CONCATENATION_EPSILON_TRANSITION;
+	static AutomataConcatenationEpsilonTransition& getInstance() {
+		static AutomataConcatenationEpsilonTransition res;
+		return res;
+	}
 };
 
 } /* namespace transform */
diff --git a/alib2algo/src/automaton/transform/AutomataIntersectionCartesianProduct.cpp b/alib2algo/src/automaton/transform/AutomataIntersectionCartesianProduct.cpp
index 187037c30e2ab79eb877e49faf1958b06af724fc..2356c905e741dfe15c72fc1841410ce3c1c48b88 100644
--- a/alib2algo/src/automaton/transform/AutomataIntersectionCartesianProduct.cpp
+++ b/alib2algo/src/automaton/transform/AutomataIntersectionCartesianProduct.cpp
@@ -12,23 +12,15 @@
 #define AUTOMATON_FIRST  1
 #define AUTOMATON_SECOND 2
 
-namespace automaton
-{
-
-namespace transform
-{
-
-automaton::Automaton AutomataIntersectionCartesianProduct::intersection(const automaton::Automaton& first, const automaton::Automaton& second)
-{
-	AutomatonBase* out;
-	Accept((void*) &out, first.getData(), second.getData(), AutomataIntersectionCartesianProduct::AUTOMATA_INTERSECTION_CARTESIAN_PRODUCT);
-	automaton::Automaton res(*out);
-	delete out;
-	return res;
+namespace automaton {
+
+namespace transform {
+
+automaton::Automaton AutomataIntersectionCartesianProduct::intersection(const automaton::Automaton& first, const automaton::Automaton& second) {
+	return getInstance().dispatch(first.getData(), second.getData());
 }
 
-automaton::DFA AutomataIntersectionCartesianProduct::intersection(const automaton::DFA& first, const automaton::DFA& second)
-{
+automaton::DFA AutomataIntersectionCartesianProduct::intersection(const automaton::DFA& first, const automaton::DFA& second) {
 	automaton::State q0(pairLabel(first.getInitialState(), second.getInitialState()));
 	automaton::DFA res(q0);
 
@@ -45,8 +37,7 @@ automaton::DFA AutomataIntersectionCartesianProduct::intersection(const automato
 		for(const auto& q : second.getFinalStates())
 			res.addFinalState(automaton::State(pairLabel(p, q)));
 
-	for(const auto& state : res.getStates())
-	{
+	for(const auto& state : res.getStates()) {
 		const label::Label& label_p = static_cast<const label::LabelPairLabel&>(state.getName().getData()).getData().first;
 		const label::Label& label_q = static_cast<const label::LabelPairLabel&>(state.getName().getData()).getData().second;
 
@@ -59,8 +50,9 @@ automaton::DFA AutomataIntersectionCartesianProduct::intersection(const automato
 	return res;
 }
 
-automaton::NFA AutomataIntersectionCartesianProduct::intersection(const automaton::NFA& first, const automaton::NFA& second)
-{
+auto AutomataIntersectionCartesianProductDFA = AutomataIntersectionCartesianProduct::RegistratorWrapper<automaton::DFA, automaton::DFA>(AutomataIntersectionCartesianProduct::getInstance(), AutomataIntersectionCartesianProduct::intersection);
+
+automaton::NFA AutomataIntersectionCartesianProduct::intersection(const automaton::NFA& first, const automaton::NFA& second) {
 	automaton::State q0(pairLabel(first.getInitialState(), second.getInitialState()));
 	automaton::NFA res(q0);
 
@@ -77,8 +69,7 @@ automaton::NFA AutomataIntersectionCartesianProduct::intersection(const automato
 		for(const auto& q : second.getFinalStates())
 			res.addFinalState(automaton::State(pairLabel(p, q)));
 
-	for(const auto& state : res.getStates())
-	{
+	for(const auto& state : res.getStates()) {
 		const label::Label& label_p = static_cast<const label::LabelPairLabel&>(state.getName().getData()).getData().first;
 		const label::Label& label_q = static_cast<const label::LabelPairLabel&>(state.getName().getData()).getData().second;
 
@@ -93,104 +84,7 @@ automaton::NFA AutomataIntersectionCartesianProduct::intersection(const automato
 	return res;
 }
 
-void AutomataIntersectionCartesianProduct::Visit(void*, const automaton::EpsilonNFA&, const automaton::EpsilonNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type EpsilonNFA");
-}
-
-void AutomataIntersectionCartesianProduct::Visit(void*, const automaton::CompactNFA&, const automaton::CompactNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type CompactNFA");
-}
-
-void AutomataIntersectionCartesianProduct::Visit(void* data, const automaton::DFA& first, const automaton::DFA& second) const
-{
-	AutomatonBase* &ret = *(AutomatonBase**) data;
-	ret = std::move(AutomataIntersectionCartesianProduct::intersection(first, second)).plunder();
-}
-
-void AutomataIntersectionCartesianProduct::Visit(void*, const automaton::ExtendedNFA&, const automaton::ExtendedNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type ExtendedNFA");
-}
-
-void AutomataIntersectionCartesianProduct::Visit(void*, const automaton::MultiInitialStateNFA&, const automaton::MultiInitialStateNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type MultiInitialStateNFA");
-}
-
-void AutomataIntersectionCartesianProduct::Visit(void* data, const automaton::NFA& first, const automaton::NFA& second) const
-{
-	AutomatonBase* &ret = *(AutomatonBase**) data;
-	ret = std::move(AutomataIntersectionCartesianProduct::intersection(first, second)).plunder();
-}
-
-void AutomataIntersectionCartesianProduct::Visit(void*, const automaton::DPDA&, const automaton::DPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type DPDA");
-}
-
-void AutomataIntersectionCartesianProduct::Visit(void*, const automaton::NPDA&, const automaton::NPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type NPDA");
-}
-
-void AutomataIntersectionCartesianProduct::Visit(void*, const automaton::InputDrivenDPDA&, const automaton::InputDrivenDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type InputDrivenDPDA");
-}
-
-void AutomataIntersectionCartesianProduct::Visit(void*, const automaton::InputDrivenNPDA&, const automaton::InputDrivenNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
-}
-
-void AutomataIntersectionCartesianProduct::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&, const automaton::RealTimeHeightDeterministicDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA");
-}
-
-void AutomataIntersectionCartesianProduct::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&, const automaton::RealTimeHeightDeterministicNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA");
-}
-
-void AutomataIntersectionCartesianProduct::Visit(void*, const automaton::SinglePopNPDA&, const automaton::SinglePopNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
-}
-
-void AutomataIntersectionCartesianProduct::Visit(void*, const automaton::SinglePopDPDA&, const automaton::SinglePopDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
-}
-
-void AutomataIntersectionCartesianProduct::Visit(void*, const automaton::VisiblyPushdownDPDA&, const automaton::VisiblyPushdownDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
-}
-
-void AutomataIntersectionCartesianProduct::Visit(void*, const automaton::VisiblyPushdownNPDA&, const automaton::VisiblyPushdownNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
-}
-
-void AutomataIntersectionCartesianProduct::Visit(void*, const automaton::OneTapeDTM&, const automaton::OneTapeDTM&) const
-{
-	throw exception::AlibException("Unsupported automaton type OneTapeDTM");
-}
-
-void AutomataIntersectionCartesianProduct::Visit(void*, const automaton::DFTA&, const automaton::DFTA&) const
-{
-	throw exception::AlibException("Unsupported automaton type DFTA");
-}
-
-void AutomataIntersectionCartesianProduct::Visit(void*, const automaton::NFTA&, const automaton::NFTA&) const
-{
-	throw exception::AlibException("Unsupported automaton type NFTA");
-}
-
-const AutomataIntersectionCartesianProduct AutomataIntersectionCartesianProduct::AUTOMATA_INTERSECTION_CARTESIAN_PRODUCT;
+auto AutomataIntersectionCartesianProductNFA = AutomataIntersectionCartesianProduct::RegistratorWrapper<automaton::NFA, automaton::NFA>(AutomataIntersectionCartesianProduct::getInstance(), AutomataIntersectionCartesianProduct::intersection);
 
 } /* namespace transform */
 
diff --git a/alib2algo/src/automaton/transform/AutomataIntersectionCartesianProduct.h b/alib2algo/src/automaton/transform/AutomataIntersectionCartesianProduct.h
index 5cba54c245c7974f97676078cb0059a4d7861dc2..824ce6f8651e855a24bab1fb32e841ed2ca2cdb8 100644
--- a/alib2algo/src/automaton/transform/AutomataIntersectionCartesianProduct.h
+++ b/alib2algo/src/automaton/transform/AutomataIntersectionCartesianProduct.h
@@ -8,54 +8,29 @@
 #ifndef AUTOMATA_INTERSECTION_CARTESIAN_H_
 #define AUTOMATA_INTERSECTION_CARTESIAN_H_
 
+#include <common/multipleDispatch.hpp>
 #include <automaton/Automaton.h>
 #include <automaton/FSM/EpsilonNFA.h>
 
-namespace automaton
-{
+namespace automaton {
 
-namespace transform
-{
+namespace transform {
 
 /**
  * Intersection of two automata.
  *  - For finite automata A1, A2, we create automaton L accepting L(A1) \cap L(A2) (Melichar, 2.75)
  */
-class AutomataIntersectionCartesianProduct : public automaton::VisitableAutomatonBase::const_promoting_visitor_type
-{
+class AutomataIntersectionCartesianProduct : public std::PromotingDoubleDispatch<automaton::Automaton, automaton::AutomatonBase> {
 public:
-	AutomataIntersectionCartesianProduct() {}
-
 	static automaton::Automaton intersection(const automaton::Automaton& first, const automaton::Automaton& second);
 
 	static automaton::NFA intersection(const automaton::NFA& first, const automaton::NFA& second);
 	static automaton::DFA intersection(const automaton::DFA& first, const automaton::DFA& second);
 
-private:
-	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::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::InputDrivenDPDA& first, const automaton::InputDrivenDPDA& second) const;
-	void Visit(void* data, const automaton::InputDrivenNPDA& first, const automaton::InputDrivenNPDA& 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;
-
-	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;
-
-	static const AutomataIntersectionCartesianProduct AUTOMATA_INTERSECTION_CARTESIAN_PRODUCT;
+	static AutomataIntersectionCartesianProduct& getInstance() {
+		static AutomataIntersectionCartesianProduct res;
+		return res;
+	}
 };
 
 } /* namespace transform */
diff --git a/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.cpp b/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.cpp
index 94ba56cbc059b638e36530e0c410d2a181ac1f9d..dd7f28889fc23a706fafb9ab6aede40d2e82a598 100644
--- a/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.cpp
+++ b/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.cpp
@@ -12,23 +12,15 @@
 #define AUTOMATON_FIRST  1
 #define AUTOMATON_SECOND 2
 
-namespace automaton
-{
-
-namespace transform
-{
-
-automaton::Automaton AutomataUnionCartesianProduct::unification(const automaton::Automaton& first, const automaton::Automaton& second)
-{
-	AutomatonBase* out;
-	Accept((void*) &out, first.getData(), second.getData(), AutomataUnionCartesianProduct::AUTOMATA_UNION_CARTESIAN_PRODUCT);
-	automaton::Automaton res(*out);
-	delete out;
-	return res;
+namespace automaton {
+
+namespace transform {
+
+automaton::Automaton AutomataUnionCartesianProduct::unification(const automaton::Automaton& first, const automaton::Automaton& second) {
+	return getInstance().dispatch(first.getData(), second.getData());
 }
 
-automaton::DFA AutomataUnionCartesianProduct::unification(const automaton::DFA& first, const automaton::DFA& second)
-{
+automaton::DFA AutomataUnionCartesianProduct::unification(const automaton::DFA& first, const automaton::DFA& second) {
 	if(!first.isTotal() || !second.isTotal())
 		throw exception::AlibException("Automata must be total to unify with cartesian product");
 
@@ -52,8 +44,7 @@ automaton::DFA AutomataUnionCartesianProduct::unification(const automaton::DFA&
 		for(const auto& q : second.getFinalStates())
 			res.addFinalState(automaton::State(pairLabel(p, q)));
 
-	for(const auto& state : res.getStates())
-	{
+	for(const auto& state : res.getStates()) {
 		const label::Label& label_p = static_cast<const label::LabelPairLabel&>(state.getName().getData()).getData().first;
 		const label::Label& label_q = static_cast<const label::LabelPairLabel&>(state.getName().getData()).getData().second;
 
@@ -66,8 +57,9 @@ automaton::DFA AutomataUnionCartesianProduct::unification(const automaton::DFA&
 	return res;
 }
 
-automaton::NFA AutomataUnionCartesianProduct::unification(const automaton::NFA& first, const automaton::NFA& second)
-{
+auto AutomataUnionCartesianProductDFA = AutomataUnionCartesianProduct::RegistratorWrapper<automaton::DFA, automaton::DFA>(AutomataUnionCartesianProduct::getInstance(), AutomataUnionCartesianProduct::unification);
+
+automaton::NFA AutomataUnionCartesianProduct::unification(const automaton::NFA& first, const automaton::NFA& second) {
 	if(!first.isTotal() || !second.isTotal())
 		throw exception::AlibException("Automata must be total to unify with cartesian product");
 
@@ -91,8 +83,7 @@ automaton::NFA AutomataUnionCartesianProduct::unification(const automaton::NFA&
 		for(const auto& q : second.getFinalStates())
 			res.addFinalState(automaton::State(pairLabel(p, q)));
 
-	for(const auto& state : res.getStates())
-	{
+	for(const auto& state : res.getStates()) {
 		const label::Label& label_p = static_cast<const label::LabelPairLabel&>(state.getName().getData()).getData().first;
 		const label::Label& label_q = static_cast<const label::LabelPairLabel&>(state.getName().getData()).getData().second;
 
@@ -107,104 +98,7 @@ automaton::NFA AutomataUnionCartesianProduct::unification(const automaton::NFA&
 	return res;
 }
 
-void AutomataUnionCartesianProduct::Visit(void*, const automaton::EpsilonNFA&, const automaton::EpsilonNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type EpsilonNFA");
-}
-
-void AutomataUnionCartesianProduct::Visit(void*, const automaton::CompactNFA&, const automaton::CompactNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type CompactNFA");
-}
-
-void AutomataUnionCartesianProduct::Visit(void* data, const automaton::DFA& first, const automaton::DFA& second) const
-{
-	AutomatonBase* &ret = *(AutomatonBase**) data;
-	ret = std::move(AutomataUnionCartesianProduct::unification(first, second)).plunder();
-}
-
-void AutomataUnionCartesianProduct::Visit(void*, const automaton::ExtendedNFA&, const automaton::ExtendedNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type ExtendedNFA");
-}
-
-void AutomataUnionCartesianProduct::Visit(void*, const automaton::MultiInitialStateNFA&, const automaton::MultiInitialStateNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type MultiInitialStateNFA");
-}
-
-void AutomataUnionCartesianProduct::Visit(void* data, const automaton::NFA& first, const automaton::NFA& second) const
-{
-	AutomatonBase* &ret = *(AutomatonBase**) data;
-	ret = std::move(AutomataUnionCartesianProduct::unification(first, second)).plunder();
-}
-
-void AutomataUnionCartesianProduct::Visit(void*, const automaton::DPDA&, const automaton::DPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type DPDA");
-}
-
-void AutomataUnionCartesianProduct::Visit(void*, const automaton::NPDA&, const automaton::NPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type NPDA");
-}
-
-void AutomataUnionCartesianProduct::Visit(void*, const automaton::InputDrivenDPDA&, const automaton::InputDrivenDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type InputDrivenDPDA");
-}
-
-void AutomataUnionCartesianProduct::Visit(void*, const automaton::InputDrivenNPDA&, const automaton::InputDrivenNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
-}
-
-void AutomataUnionCartesianProduct::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&, const automaton::RealTimeHeightDeterministicDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA");
-}
-
-void AutomataUnionCartesianProduct::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&, const automaton::RealTimeHeightDeterministicNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA");
-}
-
-void AutomataUnionCartesianProduct::Visit(void*, const automaton::SinglePopNPDA&, const automaton::SinglePopNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
-}
-
-void AutomataUnionCartesianProduct::Visit(void*, const automaton::SinglePopDPDA&, const automaton::SinglePopDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
-}
-
-void AutomataUnionCartesianProduct::Visit(void*, const automaton::VisiblyPushdownDPDA&, const automaton::VisiblyPushdownDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
-}
-
-void AutomataUnionCartesianProduct::Visit(void*, const automaton::VisiblyPushdownNPDA&, const automaton::VisiblyPushdownNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
-}
-
-void AutomataUnionCartesianProduct::Visit(void*, const automaton::OneTapeDTM&, const automaton::OneTapeDTM&) const
-{
-	throw exception::AlibException("Unsupported automaton type OneTapeDTM");
-}
-
-void AutomataUnionCartesianProduct::Visit(void*, const automaton::DFTA&, const automaton::DFTA&) const
-{
-	throw exception::AlibException("Unsupported automaton type DFTA");
-}
-
-void AutomataUnionCartesianProduct::Visit(void*, const automaton::NFTA&, const automaton::NFTA&) const
-{
-	throw exception::AlibException("Unsupported automaton type NFTA");
-}
-
-const AutomataUnionCartesianProduct AutomataUnionCartesianProduct::AUTOMATA_UNION_CARTESIAN_PRODUCT;
+auto AutomataUnionCartesianProductNFA = AutomataUnionCartesianProduct::RegistratorWrapper<automaton::NFA, automaton::NFA>(AutomataUnionCartesianProduct::getInstance(), AutomataUnionCartesianProduct::unification);
 
 } /* namespace transform */
 
diff --git a/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.h b/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.h
index a06aed29c39046166d46ba32300bf4256b253e22..7ab7cc0baa03a05ec8f5f81e02c17975863db410 100644
--- a/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.h
+++ b/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.h
@@ -8,54 +8,29 @@
 #ifndef AUTOMATA_UNION_CARTESIAN_H_
 #define AUTOMATA_UNION_CARTESIAN_H_
 
+#include <common/multipleDispatch.hpp>
 #include <automaton/Automaton.h>
 #include <automaton/FSM/EpsilonNFA.h>
 
-namespace automaton
-{
+namespace automaton {
 
-namespace transform
-{
+namespace transform {
 
 /**
  * Union two automata.
  *  - For finite automata A1, A2, we create automaton L accepting L(A1) \cup L(A2) (Melichar, 2.71)
  */
-class AutomataUnionCartesianProduct : public automaton::VisitableAutomatonBase::const_promoting_visitor_type
-{
+class AutomataUnionCartesianProduct : public std::PromotingDoubleDispatch<automaton::Automaton, automaton::AutomatonBase> {
 public:
-	AutomataUnionCartesianProduct() {}
-
 	static automaton::Automaton unification(const automaton::Automaton& first, const automaton::Automaton& second);
 
 	static automaton::NFA unification(const automaton::NFA& first, const automaton::NFA& second);
 	static automaton::DFA unification(const automaton::DFA& first, const automaton::DFA& second);
 
-private:
-	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::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::InputDrivenDPDA& first, const automaton::InputDrivenDPDA& second) const;
-	void Visit(void* data, const automaton::InputDrivenNPDA& first, const automaton::InputDrivenNPDA& 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;
-
-	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;
-
-	static const AutomataUnionCartesianProduct AUTOMATA_UNION_CARTESIAN_PRODUCT;
+	static AutomataUnionCartesianProduct& getInstance() {
+		static AutomataUnionCartesianProduct res;
+		return res;
+	}
 };
 
 } /* namespace transform */
diff --git a/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.cpp b/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.cpp
index a5d303b7a7d0a097a53955f1e411b4b1ac1972e6..dd2df0369c29196f4b0275b4b1dbbeb8dded79dc 100644
--- a/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.cpp
+++ b/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.cpp
@@ -12,23 +12,15 @@
 #define AUTOMATON_FIRST  1
 #define AUTOMATON_SECOND 2
 
-namespace automaton
-{
-
-namespace transform
-{
-
-automaton::Automaton AutomataUnionEpsilonTransition::unification(const automaton::Automaton& first, const automaton::Automaton& second)
-{
-	AutomatonBase* out;
-	Accept((void*) &out, first.getData(), second.getData(), AutomataUnionEpsilonTransition::AUTOMATA_UNION_EPSILON_TRANSITION);
-	automaton::Automaton res(*out);
-	delete out;
-	return res;
+namespace automaton {
+
+namespace transform {
+
+automaton::Automaton AutomataUnionEpsilonTransition::unification(const automaton::Automaton& first, const automaton::Automaton& second) {
+	return getInstance().dispatch(first.getData(), second.getData());
 }
 
-automaton::EpsilonNFA AutomataUnionEpsilonTransition::unification(const automaton::EpsilonNFA& first, const automaton::EpsilonNFA& second)
-{
+automaton::EpsilonNFA AutomataUnionEpsilonTransition::unification(const automaton::EpsilonNFA& first, const automaton::EpsilonNFA& second) {
 	std::set<automaton::State> states;
 	for(const auto& q : first.getStates())
 		states.insert(pairLabel(label::labelFrom(AUTOMATON_FIRST), q));
@@ -65,8 +57,9 @@ automaton::EpsilonNFA AutomataUnionEpsilonTransition::unification(const automato
 	return res;
 }
 
-automaton::EpsilonNFA AutomataUnionEpsilonTransition::unification(const automaton::NFA& first, const automaton::NFA& second)
-{
+auto AutomataUnionEpsilonTransitionEpsilonNFA = AutomataUnionEpsilonTransition::RegistratorWrapper<automaton::EpsilonNFA, automaton::EpsilonNFA>(AutomataUnionEpsilonTransition::getInstance(), AutomataUnionEpsilonTransition::unification);
+
+automaton::EpsilonNFA AutomataUnionEpsilonTransition::unification(const automaton::NFA& first, const automaton::NFA& second) {
 	std::set<automaton::State> states;
 	for(const auto& q : first.getStates())
 		states.insert(pairLabel(label::labelFrom(AUTOMATON_FIRST), q));
@@ -103,8 +96,9 @@ automaton::EpsilonNFA AutomataUnionEpsilonTransition::unification(const automato
 	return res;
 }
 
-automaton::EpsilonNFA AutomataUnionEpsilonTransition::unification(const automaton::DFA& first, const automaton::DFA& second)
-{
+auto AutomataUnionEpsilonTransitionNFA = AutomataUnionEpsilonTransition::RegistratorWrapper<automaton::EpsilonNFA, automaton::NFA>(AutomataUnionEpsilonTransition::getInstance(), AutomataUnionEpsilonTransition::unification);
+
+automaton::EpsilonNFA AutomataUnionEpsilonTransition::unification(const automaton::DFA& first, const automaton::DFA& second) {
 	std::set<automaton::State> states;
 	for(const auto& q : first.getStates())
 		states.insert(pairLabel(label::labelFrom(AUTOMATON_FIRST), q));
@@ -139,105 +133,7 @@ automaton::EpsilonNFA AutomataUnionEpsilonTransition::unification(const automato
 	return res;
 }
 
-void AutomataUnionEpsilonTransition::Visit(void* data, const automaton::EpsilonNFA& first, const automaton::EpsilonNFA& second) const
-{
-	AutomatonBase* &ret = *(AutomatonBase**) data;
-	ret = std::move(AutomataUnionEpsilonTransition::unification(first, second)).plunder();
-}
-
-void AutomataUnionEpsilonTransition::Visit(void*, const automaton::CompactNFA&, const automaton::CompactNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type CompactNFA");
-}
-
-void AutomataUnionEpsilonTransition::Visit(void* data, const automaton::DFA& first, const automaton::DFA& second) const
-{
-	AutomatonBase* &ret = *(AutomatonBase**) data;
-	ret = std::move(AutomataUnionEpsilonTransition::unification(first, second)).plunder();
-}
-
-void AutomataUnionEpsilonTransition::Visit(void*, const automaton::ExtendedNFA&, const automaton::ExtendedNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type ExtendedNFA");
-}
-
-void AutomataUnionEpsilonTransition::Visit(void*, const automaton::MultiInitialStateNFA&, const automaton::MultiInitialStateNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type MultiInitialStateNFA");
-}
-
-void AutomataUnionEpsilonTransition::Visit(void* data, const automaton::NFA& first, const automaton::NFA& second) const
-{
-	AutomatonBase* &ret = *(AutomatonBase**) data;
-	ret = std::move(AutomataUnionEpsilonTransition::unification(first, second)).plunder();
-}
-
-void AutomataUnionEpsilonTransition::Visit(void*, const automaton::DPDA&, const automaton::DPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type DPDA");
-}
-
-void AutomataUnionEpsilonTransition::Visit(void*, const automaton::NPDA&, const automaton::NPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type NPDA");
-}
-
-void AutomataUnionEpsilonTransition::Visit(void*, const automaton::InputDrivenDPDA&, const automaton::InputDrivenDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type InputDrivenDPDA");
-}
-
-void AutomataUnionEpsilonTransition::Visit(void*, const automaton::InputDrivenNPDA&, const automaton::InputDrivenNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
-}
-
-void AutomataUnionEpsilonTransition::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&, const automaton::RealTimeHeightDeterministicDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA");
-}
-
-void AutomataUnionEpsilonTransition::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&, const automaton::RealTimeHeightDeterministicNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA");
-}
-
-void AutomataUnionEpsilonTransition::Visit(void*, const automaton::SinglePopNPDA&, const automaton::SinglePopNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
-}
-
-void AutomataUnionEpsilonTransition::Visit(void*, const automaton::SinglePopDPDA&, const automaton::SinglePopDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
-}
-
-void AutomataUnionEpsilonTransition::Visit(void*, const automaton::VisiblyPushdownDPDA&, const automaton::VisiblyPushdownDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
-}
-
-void AutomataUnionEpsilonTransition::Visit(void*, const automaton::VisiblyPushdownNPDA&, const automaton::VisiblyPushdownNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
-}
-
-void AutomataUnionEpsilonTransition::Visit(void*, const automaton::OneTapeDTM&, const automaton::OneTapeDTM&) const
-{
-	throw exception::AlibException("Unsupported automaton type OneTapeDTM");
-}
-
-void AutomataUnionEpsilonTransition::Visit(void*, const automaton::DFTA&, const automaton::DFTA&) const
-{
-	throw exception::AlibException("Unsupported automaton type DFTA");
-}
-
-void AutomataUnionEpsilonTransition::Visit(void*, const automaton::NFTA&, const automaton::NFTA&) const
-{
-	throw exception::AlibException("Unsupported automaton type NFTA");
-}
-
-const AutomataUnionEpsilonTransition AutomataUnionEpsilonTransition::AUTOMATA_UNION_EPSILON_TRANSITION;
+auto AutomataUnionEpsilonTransitionDFA = AutomataUnionEpsilonTransition::RegistratorWrapper<automaton::EpsilonNFA, automaton::DFA>(AutomataUnionEpsilonTransition::getInstance(), AutomataUnionEpsilonTransition::unification);
 
 } /* namespace transform */
 
diff --git a/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.h b/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.h
index c367d1d76a7607dc51992ba2fcc4e24839ceabd2..c893f45c3468533c6a0f327427e504e431f20c14 100644
--- a/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.h
+++ b/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.h
@@ -8,55 +8,30 @@
 #ifndef AUTOMATA_UNION_EPSILON_H_
 #define AUTOMATA_UNION_EPSILON_H_
 
+#include <common/multipleDispatch.hpp>
 #include <automaton/Automaton.h>
 #include <automaton/FSM/EpsilonNFA.h>
 
-namespace automaton
-{
+namespace automaton {
 
-namespace transform
-{
+namespace transform {
 
 /**
  * Union two automata.
  *  - For finite automata A1, A2, we create automaton L accepting L(A1) \cup L(A2)
  */
-class AutomataUnionEpsilonTransition : public automaton::VisitableAutomatonBase::const_promoting_visitor_type
-{
+class AutomataUnionEpsilonTransition : public std::PromotingDoubleDispatch<automaton::Automaton, automaton::AutomatonBase> {
 public:
-	AutomataUnionEpsilonTransition() {}
-
 	static automaton::Automaton unification(const automaton::Automaton& first, const automaton::Automaton& second);
 
 	static automaton::EpsilonNFA unification(const automaton::EpsilonNFA& first, const automaton::EpsilonNFA& second);
 	static automaton::EpsilonNFA unification(const automaton::NFA& first, const automaton::NFA& second);
 	static automaton::EpsilonNFA unification(const automaton::DFA& first, const automaton::DFA& second);
 
-private:
-	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::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::InputDrivenDPDA& first, const automaton::InputDrivenDPDA& second) const;
-	void Visit(void* data, const automaton::InputDrivenNPDA& first, const automaton::InputDrivenNPDA& 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;
-
-	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;
-
-	static const AutomataUnionEpsilonTransition AUTOMATA_UNION_EPSILON_TRANSITION;
+	static AutomataUnionEpsilonTransition& getInstance() {
+		static AutomataUnionEpsilonTransition res;
+		return res;
+	}
 };
 
 } /* namespace transform */
diff --git a/alib2algo/src/automaton/transform/AutomatonIteration.cpp b/alib2algo/src/automaton/transform/AutomatonIteration.cpp
index c1dd029dde8c6b9c11c40a3c93f7c6cb697e0335..39af9570b50ca1579e22f7ec55c6b45e47b880c0 100644
--- a/alib2algo/src/automaton/transform/AutomatonIteration.cpp
+++ b/alib2algo/src/automaton/transform/AutomatonIteration.cpp
@@ -8,24 +8,16 @@
 #include "AutomatonIteration.h"
 #include <exception/AlibException.h>
 
-namespace automaton
-{
+namespace automaton {
 
-namespace transform
-{
+namespace transform {
 
-automaton::Automaton AutomatonIteration::iteration(const automaton::Automaton& automaton)
-{
-	AutomatonBase* out;
-	automaton.getData().Accept((void*) &out, AutomatonIteration::AUTOMATON_ITERATION);
-	automaton::Automaton res(*out);
-	delete out;
-	return res;
+automaton::Automaton AutomatonIteration::iteration(const automaton::Automaton& automaton) {
+	return getInstance().dispatch(automaton.getData());
 }
 
 template<class T>
-automaton::NFA AutomatonIteration::iteration(const T& automaton)
-{
+automaton::NFA AutomatonIteration::iteration(const T& automaton) {
 	automaton::NFA res(automaton);
 
 	for(const auto& qf : res.getFinalStates())
@@ -36,104 +28,8 @@ automaton::NFA AutomatonIteration::iteration(const T& automaton)
 	return res;
 }
 
-void AutomatonIteration::Visit(void*, const automaton::EpsilonNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type EpsilonNFA");
-}
-
-void AutomatonIteration::Visit(void*, const automaton::CompactNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type CompactNFA");
-}
-
-void AutomatonIteration::Visit(void* data, const automaton::DFA& automaton) const
-{
-	AutomatonBase* &ret = *(AutomatonBase**) data;
-	ret = std::move(AutomatonIteration::iteration(automaton)).plunder();
-}
-
-void AutomatonIteration::Visit(void*, const automaton::ExtendedNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type ExtendedNFA");
-}
-
-void AutomatonIteration::Visit(void*, const automaton::MultiInitialStateNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type MultiInitialStateNFA");
-}
-
-void AutomatonIteration::Visit(void* data, const automaton::NFA& automaton) const
-{
-	AutomatonBase* &ret = *(AutomatonBase**) data;
-	ret = std::move(AutomatonIteration::iteration(automaton)).plunder();
-}
-
-void AutomatonIteration::Visit(void*, const automaton::DPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type DPDA");
-}
-
-void AutomatonIteration::Visit(void*, const automaton::NPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type NPDA");
-}
-
-void AutomatonIteration::Visit(void*, const automaton::InputDrivenDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type InputDrivenDPDA");
-}
-
-void AutomatonIteration::Visit(void*, const automaton::InputDrivenNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
-}
-
-void AutomatonIteration::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA");
-}
-
-void AutomatonIteration::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA");
-}
-
-void AutomatonIteration::Visit(void*, const automaton::SinglePopNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
-}
-
-void AutomatonIteration::Visit(void*, const automaton::SinglePopDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
-}
-
-void AutomatonIteration::Visit(void*, const automaton::VisiblyPushdownDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
-}
-
-void AutomatonIteration::Visit(void*, const automaton::VisiblyPushdownNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
-}
-
-void AutomatonIteration::Visit(void*, const automaton::OneTapeDTM&) const
-{
-	throw exception::AlibException("Unsupported automaton type OneTapeDTM");
-}
-
-void AutomatonIteration::Visit(void*, const automaton::DFTA&) const
-{
-	throw exception::AlibException("Unsupported automaton type DFTA");
-}
-
-void AutomatonIteration::Visit(void*, const automaton::NFTA&) const
-{
-	throw exception::AlibException("Unsupported automaton type NFTA");
-}
-
-const AutomatonIteration AutomatonIteration::AUTOMATON_ITERATION;
+auto AutomatonIterationDFA = AutomatonIteration::RegistratorWrapper<automaton::NFA, automaton::DFA>(AutomatonIteration::getInstance(), AutomatonIteration::iteration);
+auto AutomatonIterationNFA = AutomatonIteration::RegistratorWrapper<automaton::NFA, automaton::NFA>(AutomatonIteration::getInstance(), AutomatonIteration::iteration);
 
 } /* namespace transform */
 
diff --git a/alib2algo/src/automaton/transform/AutomatonIteration.h b/alib2algo/src/automaton/transform/AutomatonIteration.h
index fb7d2728e817282db4d4330aeb23622f952235e5..997aa375c58b37bec6b11a60840b4c4ac719bfdc 100644
--- a/alib2algo/src/automaton/transform/AutomatonIteration.h
+++ b/alib2algo/src/automaton/transform/AutomatonIteration.h
@@ -8,54 +8,29 @@
 #ifndef AUTOMATON_ITERATION_H_
 #define AUTOMATON_ITERATION_H_
 
+#include <common/multipleDispatch.hpp>
 #include <automaton/Automaton.h>
 #include <automaton/FSM/EpsilonNFA.h>
 
-namespace automaton
-{
+namespace automaton {
 
-namespace transform
-{
+namespace transform {
 
 /**
  * Iterates language given by automaton
  *  - For finite automaton A1, we create automaton L accepting L(A1)*
  */
-class AutomatonIteration : public automaton::VisitableAutomatonBase::const_visitor_type
-{
+class AutomatonIteration : public std::SingleDispatch<automaton::Automaton, automaton::AutomatonBase> {
 public:
-	AutomatonIteration() {}
-
 	static automaton::Automaton iteration(const automaton::Automaton& automaton);
 
 	template<class T>
 	static automaton::NFA iteration(const T& automaton);
 
-private:
-	void Visit(void* data, const automaton::CompactNFA& automaton) const;
-	void Visit(void* data, const automaton::DFA& automaton) const;
-	void Visit(void* data, const automaton::EpsilonNFA& automaton) const;
-	void Visit(void* data, const automaton::ExtendedNFA& automaton) const;
-	void Visit(void* data, const automaton::MultiInitialStateNFA& automaton) const;
-	void Visit(void* data, const automaton::NFA& automaton) const;
-
-	void Visit(void* data, const automaton::DPDA& automaton) const;
-	void Visit(void* data, const automaton::NPDA& automaton) const;
-	void Visit(void* data, const automaton::InputDrivenDPDA& automaton) const;
-	void Visit(void* data, const automaton::InputDrivenNPDA& automaton) const;
-	void Visit(void* data, const automaton::RealTimeHeightDeterministicDPDA& automaton) const;
-	void Visit(void* data, const automaton::RealTimeHeightDeterministicNPDA& automaton) const;
-	void Visit(void* data, const automaton::SinglePopNPDA& automaton) const;
-	void Visit(void* data, const automaton::SinglePopDPDA& automaton) const;
-	void Visit(void* data, const automaton::VisiblyPushdownDPDA& automaton) const;
-	void Visit(void* data, const automaton::VisiblyPushdownNPDA& automaton) const;
-
-	void Visit(void* data, const automaton::OneTapeDTM& automaton) const;
-
-	void Visit(void* data, const automaton::DFTA& first) const;
-	void Visit(void* data, const automaton::NFTA& first) const;
-
-	static const AutomatonIteration AUTOMATON_ITERATION;
+	static AutomatonIteration& getInstance() {
+		static AutomatonIteration res;
+		return res;
+	}
 };
 
 } /* namespace transform */
diff --git a/alib2algo/src/automaton/transform/AutomatonIterationEpsilonTransition.cpp b/alib2algo/src/automaton/transform/AutomatonIterationEpsilonTransition.cpp
index 739a8f57275f28b50081fc6dd8b420ef0ce493e3..4f839d37528d6ac8d596302ac811d99c7c0d36b0 100644
--- a/alib2algo/src/automaton/transform/AutomatonIterationEpsilonTransition.cpp
+++ b/alib2algo/src/automaton/transform/AutomatonIterationEpsilonTransition.cpp
@@ -8,24 +8,16 @@
 #include "AutomatonIterationEpsilonTransition.h"
 #include <exception/AlibException.h>
 
-namespace automaton
-{
+namespace automaton {
 
-namespace transform
-{
+namespace transform {
 
-automaton::Automaton AutomatonIterationEpsilonTransition::iteration(const automaton::Automaton& automaton)
-{
-	AutomatonBase* out;
-	automaton.getData().Accept((void*) &out, AutomatonIterationEpsilonTransition::AUTOMATON_ITERATION_EPSILON_TRANSITION);
-	automaton::Automaton res(*out);
-	delete out;
-	return res;
+automaton::Automaton AutomatonIterationEpsilonTransition::iteration(const automaton::Automaton& automaton) {
+	return getInstance().dispatch(automaton.getData());
 }
 
 template<class T>
-automaton::EpsilonNFA AutomatonIterationEpsilonTransition::iteration(const T& automaton)
-{
+automaton::EpsilonNFA AutomatonIterationEpsilonTransition::iteration(const T& automaton) {
 	automaton::EpsilonNFA res(automaton);
 
 	for(const auto&q : automaton.getFinalStates())
@@ -35,105 +27,9 @@ automaton::EpsilonNFA AutomatonIterationEpsilonTransition::iteration(const T& au
 	return res;
 }
 
-void AutomatonIterationEpsilonTransition::Visit(void* data, const automaton::EpsilonNFA& automaton) const
-{
-	AutomatonBase* &ret = *(AutomatonBase**) data;
-	ret = std::move(AutomatonIterationEpsilonTransition::iteration(automaton)).plunder();
-}
-
-void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::CompactNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type CompactNFA");
-}
-
-void AutomatonIterationEpsilonTransition::Visit(void* data, const automaton::DFA& automaton) const
-{
-	AutomatonBase* &ret = *(AutomatonBase**) data;
-	ret = std::move(AutomatonIterationEpsilonTransition::iteration(automaton)).plunder();
-}
-
-void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::ExtendedNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type ExtendedNFA");
-}
-
-void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::MultiInitialStateNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type MultiInitialStateNFA");
-}
-
-void AutomatonIterationEpsilonTransition::Visit(void* data, const automaton::NFA& automaton) const
-{
-	AutomatonBase* &ret = *(AutomatonBase**) data;
-	ret = std::move(AutomatonIterationEpsilonTransition::iteration(automaton)).plunder();
-}
-
-void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::DPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type DPDA");
-}
-
-void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::NPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type NPDA");
-}
-
-void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::InputDrivenDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type InputDrivenDPDA");
-}
-
-void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::InputDrivenNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
-}
-
-void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::RealTimeHeightDeterministicDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicDPDA");
-}
-
-void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::RealTimeHeightDeterministicNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type RealTimeHeightDeterministicNPDA");
-}
-
-void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::SinglePopNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
-}
-
-void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::SinglePopDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
-}
-
-void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::VisiblyPushdownDPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
-}
-
-void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::VisiblyPushdownNPDA&) const
-{
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
-}
-
-void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::OneTapeDTM&) const
-{
-	throw exception::AlibException("Unsupported automaton type OneTapeDTM");
-}
-
-void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::DFTA&) const
-{
-	throw exception::AlibException("Unsupported automaton type DFTA");
-}
-
-void AutomatonIterationEpsilonTransition::Visit(void*, const automaton::NFTA&) const
-{
-	throw exception::AlibException("Unsupported automaton type NFTA");
-}
-
-const AutomatonIterationEpsilonTransition AutomatonIterationEpsilonTransition::AUTOMATON_ITERATION_EPSILON_TRANSITION;
+auto AutomatonIterationEpsilonTransitionDFA = AutomatonIterationEpsilonTransition::RegistratorWrapper<automaton::EpsilonNFA, automaton::DFA>(AutomatonIterationEpsilonTransition::getInstance(), AutomatonIterationEpsilonTransition::iteration);
+auto AutomatonIterationEpsilonTransitionNFA = AutomatonIterationEpsilonTransition::RegistratorWrapper<automaton::EpsilonNFA, automaton::NFA>(AutomatonIterationEpsilonTransition::getInstance(), AutomatonIterationEpsilonTransition::iteration);
+auto AutomatonIterationEpsilonTransitionEpsilonNFA = AutomatonIterationEpsilonTransition::RegistratorWrapper<automaton::EpsilonNFA, automaton::EpsilonNFA>(AutomatonIterationEpsilonTransition::getInstance(), AutomatonIterationEpsilonTransition::iteration);
 
 } /* namespace transform */
 
diff --git a/alib2algo/src/automaton/transform/AutomatonIterationEpsilonTransition.h b/alib2algo/src/automaton/transform/AutomatonIterationEpsilonTransition.h
index 307d6c55fec5f115acaedb1d6f9d4e152bdfe2d2..c9f7cb3365ede30a2c6924fc8619359c7dd31e1e 100644
--- a/alib2algo/src/automaton/transform/AutomatonIterationEpsilonTransition.h
+++ b/alib2algo/src/automaton/transform/AutomatonIterationEpsilonTransition.h
@@ -8,54 +8,29 @@
 #ifndef AUTOMATON_ITERATION_EPSILON_TRANSITION_H_
 #define AUTOMATON_ITERATION_EPSILON_TRANSITION_H_
 
+#include <common/multipleDispatch.hpp>
 #include <automaton/Automaton.h>
 #include <automaton/FSM/EpsilonNFA.h>
 
-namespace automaton
-{
+namespace automaton {
 
-namespace transform
-{
+namespace transform {
 
 /**
  * Iterates language given by automaton
  *  - For finite automaton A1, we create automaton L accepting L(A1)*
  */
-class AutomatonIterationEpsilonTransition : public automaton::VisitableAutomatonBase::const_visitor_type
-{
+class AutomatonIterationEpsilonTransition : public std::SingleDispatch<automaton::Automaton, automaton::AutomatonBase> {
 public:
-	AutomatonIterationEpsilonTransition() {}
-
 	static automaton::Automaton iteration(const automaton::Automaton& automaton);
 
 	template<class T>
 	static automaton::EpsilonNFA iteration(const T& automaton);
 
-private:
-	void Visit(void* data, const automaton::CompactNFA& automaton) const;
-	void Visit(void* data, const automaton::DFA& automaton) const;
-	void Visit(void* data, const automaton::EpsilonNFA& automaton) const;
-	void Visit(void* data, const automaton::ExtendedNFA& automaton) const;
-	void Visit(void* data, const automaton::MultiInitialStateNFA& automaton) const;
-	void Visit(void* data, const automaton::NFA& automaton) const;
-
-	void Visit(void* data, const automaton::DPDA& automaton) const;
-	void Visit(void* data, const automaton::NPDA& automaton) const;
-	void Visit(void* data, const automaton::InputDrivenDPDA& automaton) const;
-	void Visit(void* data, const automaton::InputDrivenNPDA& automaton) const;
-	void Visit(void* data, const automaton::RealTimeHeightDeterministicDPDA& automaton) const;
-	void Visit(void* data, const automaton::RealTimeHeightDeterministicNPDA& automaton) const;
-	void Visit(void* data, const automaton::SinglePopNPDA& automaton) const;
-	void Visit(void* data, const automaton::SinglePopDPDA& automaton) const;
-	void Visit(void* data, const automaton::VisiblyPushdownDPDA& automaton) const;
-	void Visit(void* data, const automaton::VisiblyPushdownNPDA& automaton) const;
-
-	void Visit(void* data, const automaton::OneTapeDTM& automaton) const;
-
-	void Visit(void* data, const automaton::DFTA& first) const;
-	void Visit(void* data, const automaton::NFTA& first) const;
-
-	static const AutomatonIterationEpsilonTransition AUTOMATON_ITERATION_EPSILON_TRANSITION;
+	static AutomatonIterationEpsilonTransition& getInstance() {
+		static AutomatonIterationEpsilonTransition res;
+		return res;
+	}
 };
 
 } /* namespace transform */
diff --git a/alib2algo/src/automaton/transform/Compaction.cpp b/alib2algo/src/automaton/transform/Compaction.cpp
index 1563cdefdd90c8703ab7a357b2940fa4979fdd3b..3e61aac160eca3f9d0ce34f0e9000d2e1043ec83 100644
--- a/alib2algo/src/automaton/transform/Compaction.cpp
+++ b/alib2algo/src/automaton/transform/Compaction.cpp
@@ -21,20 +21,16 @@ namespace automaton {
 namespace transform {
 
 automaton::Automaton Compaction::convert(const automaton::Automaton& automaton) {
-	automaton::Automaton* out = NULL;
-	automaton.getData().Accept((void*) &out, Compaction::COMPACTION);
-	automaton::Automaton res(std::move(*out));
-	delete out;
-	return res;
+	return getInstance().dispatch(automaton.getData());
 }
 
-automaton::CompactNFA Compaction::convert(const automaton::CompactNFA& automaton)
-{
+automaton::CompactNFA Compaction::convert(const automaton::CompactNFA& automaton) {
 	return automaton;
 }
 
-automaton::CompactNFA Compaction::convert(const automaton::DFA& automaton)
-{
+auto CompactionCompactNFA = Compaction::RegistratorWrapper<automaton::CompactNFA, automaton::CompactNFA>(Compaction::getInstance(), Compaction::convert);
+
+automaton::CompactNFA Compaction::convert(const automaton::DFA& automaton) {
 	automaton::CompactNFA res(automaton.getInitialState());
 	res.setInputAlphabet(automaton.getInputAlphabet());
 
@@ -80,47 +76,15 @@ automaton::CompactNFA Compaction::convert(const automaton::DFA& automaton)
 	return res;
 }
 
-automaton::CompactNFA Compaction::convert(const automaton::NFA& automaton)
-{
+auto CompactionDFA = Compaction::RegistratorWrapper<automaton::CompactNFA, automaton::DFA>(Compaction::getInstance(), Compaction::convert);
+
+automaton::CompactNFA Compaction::convert(const automaton::NFA& automaton) {
 	automaton::CompactNFA res(automaton.getInitialState());
 	// TODO
 	return res;
 }
 
-void Compaction::Visit(void* data, const CompactNFA& automaton) const
-{
-	automaton::Automaton*& out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->convert(automaton));
-}
-
-void Compaction::Visit(void* data, const DFA& automaton) const
-{
-	automaton::Automaton*& out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->convert(automaton));
-}
-
-void Compaction::Visit(void*, const EpsilonNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type EpsilonNFA");
-}
-
-void Compaction::Visit(void*, const ExtendedNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type ExtendedNFA");
-}
-
-void Compaction::Visit(void*, const MultiInitialStateNFA&) const
-{
-	throw exception::AlibException("Unsupported automaton type MultiInitialStateNFA");
-}
-
-void Compaction::Visit(void* data, const NFA& automaton) const
-{
-	automaton::Automaton*& out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->convert(automaton));
-}
-
-const Compaction Compaction::COMPACTION;
+auto CompactionNFA = Compaction::RegistratorWrapper<automaton::CompactNFA, automaton::NFA>(Compaction::getInstance(), Compaction::convert);
 
 } /* namespace transform */
 
diff --git a/alib2algo/src/automaton/transform/Compaction.h b/alib2algo/src/automaton/transform/Compaction.h
index e0da50de241a9bc60a33b67112a9e0b779552c99..1300602ef2e53480b950bb284a32181a8107a1e4 100644
--- a/alib2algo/src/automaton/transform/Compaction.h
+++ b/alib2algo/src/automaton/transform/Compaction.h
@@ -8,6 +8,7 @@
 #ifndef COMPACTION_H_
 #define COMPACTION_H_
 
+#include <common/multipleDispatch.hpp>
 #include "automaton/Automaton.h"
 
 namespace automaton {
@@ -17,10 +18,8 @@ namespace transform {
 /**
  * Transforms FSM to CompactNFA
  */
-class Compaction : public automaton::VisitableConstFSMBase {
+class Compaction : public std::SingleDispatch<automaton::Automaton, automaton::AutomatonBase> {
 public:
-	Compaction() {}
-
 	static automaton::CompactNFA convert( const automaton::DFA& automaton);
 	static automaton::CompactNFA convert( const automaton::NFA& automaton);
 	static automaton::CompactNFA convert( const automaton::CompactNFA& automaton);
@@ -32,17 +31,10 @@ public:
 	 */
 	static automaton::Automaton convert( const automaton::Automaton & automaton );
 
-private:
-	using automaton::VisitableConstFSMBase::Visit;
-
-	void Visit(void*, const CompactNFA& automaton) const;
-	void Visit(void*, const DFA& automaton) const;
-	void Visit(void*, const EpsilonNFA& automaton) const;
-	void Visit(void*, const ExtendedNFA& automaton) const;
-	void Visit(void*, const MultiInitialStateNFA& automaton) const;
-	void Visit(void*, const NFA& automaton) const;
-
-	static const Compaction COMPACTION;
+	static Compaction& getInstance() {
+		static Compaction res;
+		return res;
+	}
 };
 
 } /* namespace transform */
diff --git a/alib2algo/src/automaton/transform/PDAToRHPDA.cpp b/alib2algo/src/automaton/transform/PDAToRHPDA.cpp
index 68c0d9efa40856c458438194617183a79b88ffce..a53cca884c23d5cb2576c203bfdac215a620e503 100644
--- a/alib2algo/src/automaton/transform/PDAToRHPDA.cpp
+++ b/alib2algo/src/automaton/transform/PDAToRHPDA.cpp
@@ -25,10 +25,14 @@ automaton::RealTimeHeightDeterministicDPDA PDAToRHPDA::convert( const automaton:
 	return pda;
 }
 
+auto PDAToRHPDARealTimeHeightDeterministicDPDA = PDAToRHPDA::RegistratorWrapper<automaton::RealTimeHeightDeterministicDPDA, automaton::RealTimeHeightDeterministicDPDA>(PDAToRHPDA::getInstance(), PDAToRHPDA::convert);
+
 automaton::RealTimeHeightDeterministicNPDA PDAToRHPDA::convert( const automaton::RealTimeHeightDeterministicNPDA & pda ) {
 	return pda;
 }
 
+auto PDAToRHPDARealTimeHeightDeterministicNPDA = PDAToRHPDA::RegistratorWrapper<automaton::RealTimeHeightDeterministicNPDA, automaton::RealTimeHeightDeterministicNPDA>(PDAToRHPDA::getInstance(), PDAToRHPDA::convert);
+
 automaton::RealTimeHeightDeterministicDPDA PDAToRHPDA::convert( const automaton::DPDA & pda ) {
 	automaton::State q0 = automaton::createUniqueState(automaton::State("q0"), pda.getStates());
 
@@ -93,6 +97,8 @@ automaton::RealTimeHeightDeterministicDPDA PDAToRHPDA::convert( const automaton:
 	return res;
 }
 
+auto PDAToRHPDADPDA = PDAToRHPDA::RegistratorWrapper<automaton::RealTimeHeightDeterministicDPDA, automaton::DPDA>(PDAToRHPDA::getInstance(), PDAToRHPDA::convert);
+
 automaton::RealTimeHeightDeterministicNPDA PDAToRHPDA::convert( const automaton::NPDA & pda ) {
 	RealTimeHeightDeterministicNPDA res(alphabet::Symbol { alphabet::BottomOfTheStackSymbol::BOTTOM_OF_THE_STACK } );
 
@@ -159,59 +165,11 @@ automaton::RealTimeHeightDeterministicNPDA PDAToRHPDA::convert( const automaton:
 	return res;
 }
 
-automaton::Automaton PDAToRHPDA::convert(const Automaton& automaton) {
-	automaton::Automaton* out = NULL;
-	automaton.getData().Accept((void*) &out, PDAToRHPDA::PDA_TO_RHPDA);
-	automaton::Automaton res(std::move(*out));
-	delete out;
-	return std::move(res);
-}
-
-void PDAToRHPDA::Visit(void* data, const DPDA& automaton) const {
-	automaton::Automaton*& out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->convert(automaton));
-}
-
-void PDAToRHPDA::Visit(void*, const SinglePopDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
-}
-
-void PDAToRHPDA::Visit(void*, const InputDrivenDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenDPDA");
-}
-
-void PDAToRHPDA::Visit(void*, const InputDrivenNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
-}
+auto PDAToRHPDANPDA = PDAToRHPDA::RegistratorWrapper<automaton::RealTimeHeightDeterministicNPDA, automaton::NPDA>(PDAToRHPDA::getInstance(), PDAToRHPDA::convert);
 
-void PDAToRHPDA::Visit(void*, const VisiblyPushdownDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
-}
-
-void PDAToRHPDA::Visit(void*, const VisiblyPushdownNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
-}
-
-void PDAToRHPDA::Visit(void* data, const RealTimeHeightDeterministicDPDA& automaton) const {
-	automaton::Automaton*& out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->convert(automaton));
-}
-
-void PDAToRHPDA::Visit(void* data, const RealTimeHeightDeterministicNPDA& automaton) const {
-	automaton::Automaton*& out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->convert(automaton));
-}
-
-void PDAToRHPDA::Visit(void* data, const NPDA& automaton) const {
-	automaton::Automaton*& out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->convert(automaton));
-}
-
-void PDAToRHPDA::Visit(void*, const SinglePopNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
+automaton::Automaton PDAToRHPDA::convert(const Automaton& automaton) {
+	return getInstance().dispatch(automaton.getData());
 }
 
-const PDAToRHPDA PDAToRHPDA::PDA_TO_RHPDA;
-
 }
 
diff --git a/alib2algo/src/automaton/transform/PDAToRHPDA.h b/alib2algo/src/automaton/transform/PDAToRHPDA.h
index 504043797daf98e566db46c2b6bde0b94ef5707b..6a6ff0c69527b40e5e919d0e10c12f0bd1467424 100644
--- a/alib2algo/src/automaton/transform/PDAToRHPDA.h
+++ b/alib2algo/src/automaton/transform/PDAToRHPDA.h
@@ -8,6 +8,7 @@
 #ifndef PDA_TO_RHPDA_H_
 #define PDA_TO_RHPDA_H_
 
+#include <common/multipleDispatch.hpp>
 #include <algorithm>
 #include <deque>
 #include <set>
@@ -17,10 +18,8 @@
 
 namespace automaton {
 
-class PDAToRHPDA : public automaton::VisitableConstPDABase {
+class PDAToRHPDA : public std::SingleDispatch<automaton::Automaton, automaton::AutomatonBase> {
 public:
-	PDAToRHPDA() {}
-
 	static automaton::RealTimeHeightDeterministicDPDA convert( const automaton::RealTimeHeightDeterministicDPDA & pda);
 	static automaton::RealTimeHeightDeterministicDPDA convert( const automaton::DPDA & pda);
 	static automaton::RealTimeHeightDeterministicNPDA convert( const automaton::RealTimeHeightDeterministicNPDA & pda);
@@ -30,21 +29,11 @@ public:
 	 * Computes epsilon closure of a state in epsilon nonfree automaton
 	 */
 	static automaton::Automaton convert( const automaton::Automaton & automaton );
-private:
-	using automaton::VisitableConstPDABase::Visit;
-
-	void Visit(void*, const DPDA& automaton) const;
-	void Visit(void*, const SinglePopDPDA& automaton) const;
-	void Visit(void*, const InputDrivenNPDA& automaton) const;
-	void Visit(void*, const InputDrivenDPDA& automaton) const;
-	void Visit(void*, const VisiblyPushdownDPDA& automaton) const;
-	void Visit(void*, const VisiblyPushdownNPDA& automaton) const;
-	void Visit(void*, const RealTimeHeightDeterministicDPDA& automaton) const;
-	void Visit(void*, const RealTimeHeightDeterministicNPDA& automaton) const;
-	void Visit(void*, const NPDA& automaton) const;
-	void Visit(void*, const SinglePopNPDA& automaton) const;
-
-	static const PDAToRHPDA PDA_TO_RHPDA;
+
+	static PDAToRHPDA& getInstance() {
+		static PDAToRHPDA res;
+		return res;
+	}
 };
 
 }
diff --git a/alib2algo/src/automaton/transform/RHPDAToPDA.cpp b/alib2algo/src/automaton/transform/RHPDAToPDA.cpp
index 0e6e03742095131e208067d53c576e0b7b32deba..9789850625dc12412046a1d95d7df2b1da0195ba 100644
--- a/alib2algo/src/automaton/transform/RHPDAToPDA.cpp
+++ b/alib2algo/src/automaton/transform/RHPDAToPDA.cpp
@@ -128,6 +128,8 @@ automaton::DPDA RHPDAToPDA::convert( const automaton::RealTimeHeightDeterministi
 	return res;
 }
 
+auto RHPDAToPDARealTimeHeightDeterministicDPDA = RHPDAToPDA::RegistratorWrapper<automaton::DPDA, automaton::RealTimeHeightDeterministicDPDA>(RHPDAToPDA::getInstance(), RHPDAToPDA::convert);
+
 //This may not work correctly -- generation of initial state and initial symbol
 automaton::NPDA RHPDAToPDA::convert( const automaton::RealTimeHeightDeterministicNPDA & pda ) {
 	std::map<std::tuple<automaton::State, alphabet::Symbol, std::vector<alphabet::Symbol>>, std::set<std::pair<automaton::State, std::vector<alphabet::Symbol>>>> readingTransitions;
@@ -247,57 +249,11 @@ automaton::NPDA RHPDAToPDA::convert( const automaton::RealTimeHeightDeterministi
 	return res;
 }
 
-automaton::Automaton RHPDAToPDA::convert(const Automaton& automaton) {
-	automaton::Automaton* out = NULL;
-	automaton.getData().Accept((void*) &out, RHPDAToPDA::RHPDA_TO_PDA);
-	automaton::Automaton res(std::move(*out));
-	delete out;
-	return std::move(res);
-}
-
-void RHPDAToPDA::Visit(void*, const DPDA&) const {
-	throw exception::AlibException("Unsupported automaton type DPDA");
-}
-
-void RHPDAToPDA::Visit(void*, const SinglePopDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopDPDA");
-}
-
-void RHPDAToPDA::Visit(void*, const InputDrivenDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenDPDA");
-}
+auto RHPDAToPDARealTimeHeightDeterministicNPDA = RHPDAToPDA::RegistratorWrapper<automaton::NPDA, automaton::RealTimeHeightDeterministicNPDA>(RHPDAToPDA::getInstance(), RHPDAToPDA::convert);
 
-void RHPDAToPDA::Visit(void*, const InputDrivenNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type InputDrivenNPDA");
-}
-
-void RHPDAToPDA::Visit(void*, const VisiblyPushdownDPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownDPDA");
-}
-
-void RHPDAToPDA::Visit(void*, const VisiblyPushdownNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type VisiblyPushdownNPDA");
-}
-
-void RHPDAToPDA::Visit(void* data, const RealTimeHeightDeterministicDPDA& automaton) const {
-	automaton::Automaton*& out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->convert(automaton));
-}
-
-void RHPDAToPDA::Visit(void* data, const RealTimeHeightDeterministicNPDA& automaton) const {
-	automaton::Automaton*& out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->convert(automaton));
-}
-
-void RHPDAToPDA::Visit(void*, const NPDA&) const {
-	throw exception::AlibException("Unsupported automaton type NPDA");
-}
-
-void RHPDAToPDA::Visit(void*, const SinglePopNPDA&) const {
-	throw exception::AlibException("Unsupported automaton type SinglePopNPDA");
+automaton::Automaton RHPDAToPDA::convert(const Automaton& automaton) {
+	return getInstance().dispatch(automaton.getData());
 }
 
-const RHPDAToPDA RHPDAToPDA::RHPDA_TO_PDA;
-
 }
 
diff --git a/alib2algo/src/automaton/transform/RHPDAToPDA.h b/alib2algo/src/automaton/transform/RHPDAToPDA.h
index fe256487c7f6c94c17e5e61c22a381bdcecbcbe1..7763e7ca3cc1ca36e7dd3e5412eebc29328b66d4 100644
--- a/alib2algo/src/automaton/transform/RHPDAToPDA.h
+++ b/alib2algo/src/automaton/transform/RHPDAToPDA.h
@@ -8,6 +8,7 @@
 #ifndef RHPDA_TO_PDA_H_
 #define RHPDA_TO_PDA_H_
 
+#include <common/multipleDispatch.hpp>
 #include <algorithm>
 #include <deque>
 #include <set>
@@ -17,10 +18,8 @@
 
 namespace automaton {
 
-class RHPDAToPDA : public VisitableConstPDABase {
+class RHPDAToPDA : public std::SingleDispatch<automaton::Automaton, automaton::AutomatonBase> {
 public:
-	RHPDAToPDA() {}
-
 	static automaton::DPDA convert( const automaton::RealTimeHeightDeterministicDPDA & pda);
 	static automaton::DPDA convert( const automaton::DPDA & pda);
 	static automaton::NPDA convert( const automaton::RealTimeHeightDeterministicNPDA & pda);
@@ -30,21 +29,11 @@ public:
 	 * Computes epsilon closure of a state in epsilon nonfree automaton
 	 */
 	static automaton::Automaton convert( const automaton::Automaton & automaton );
-private:
-	using automaton::VisitableConstPDABase::Visit;
-
-	void Visit(void*, const DPDA& automaton) const;
-	void Visit(void*, const SinglePopDPDA& automaton) const;
-	void Visit(void*, const InputDrivenDPDA& automaton) const;
-	void Visit(void*, const InputDrivenNPDA& automaton) const;
-	void Visit(void*, const VisiblyPushdownDPDA& automaton) const;
-	void Visit(void*, const VisiblyPushdownNPDA& automaton) const;
-	void Visit(void*, const RealTimeHeightDeterministicDPDA& automaton) const;
-	void Visit(void*, const RealTimeHeightDeterministicNPDA& automaton) const;
-	void Visit(void*, const NPDA& automaton) const;
-	void Visit(void*, const SinglePopNPDA& automaton) const;
-
-	static const RHPDAToPDA RHPDA_TO_PDA;
+
+	static RHPDAToPDA& getInstance() {
+		static RHPDAToPDA res;
+		return res;
+	}
 };
 
 }
diff --git a/alib2algo/src/automaton/transform/Reverse.cpp b/alib2algo/src/automaton/transform/Reverse.cpp
index 7afb8e28e1e25d28dd9ababd6fe6b337672bd3a6..f751f276015aa48fa1b4f9826e3d4dfad057c3ec 100644
--- a/alib2algo/src/automaton/transform/Reverse.cpp
+++ b/alib2algo/src/automaton/transform/Reverse.cpp
@@ -18,15 +18,10 @@ namespace automaton {
 namespace transform {
 
 automaton::Automaton Reverse::convert(const Automaton& automaton) {
-	automaton::Automaton* out = NULL;
-	automaton.getData().Accept((void*) &out, Reverse::REVERSE);
-	automaton::Automaton res(std::move(*out));
-	delete out;
-	return std::move(res);
+	return getInstance().dispatch(automaton.getData());
 }
 
-automaton::MultiInitialStateNFA Reverse::convert(const automaton::DFA& automaton)
-{
+automaton::MultiInitialStateNFA Reverse::convert(const automaton::DFA& automaton) {
 	automaton::MultiInitialStateNFA res;
 
 	res.setStates(automaton.getStates());
@@ -40,8 +35,9 @@ automaton::MultiInitialStateNFA Reverse::convert(const automaton::DFA& automaton
 	return res;
 }
 
-automaton::MultiInitialStateNFA Reverse::convert(const automaton::NFA& automaton)
-{
+auto ReverseDFA = Reverse::RegistratorWrapper<automaton::MultiInitialStateNFA, automaton::DFA>(Reverse::getInstance(), Reverse::convert);
+
+automaton::MultiInitialStateNFA Reverse::convert(const automaton::NFA& automaton) {
 	automaton::MultiInitialStateNFA res;
 
 	res.setStates(automaton.getStates());
@@ -56,8 +52,9 @@ automaton::MultiInitialStateNFA Reverse::convert(const automaton::NFA& automaton
 	return res;
 }
 
-automaton::MultiInitialStateNFA Reverse::convert(const automaton::MultiInitialStateNFA& automaton)
-{
+auto ReverseNFA = Reverse::RegistratorWrapper<automaton::MultiInitialStateNFA, automaton::NFA>(Reverse::getInstance(), Reverse::convert);
+
+automaton::MultiInitialStateNFA Reverse::convert(const automaton::MultiInitialStateNFA& automaton) {
 	automaton::MultiInitialStateNFA res;
 
 	res.setStates(automaton.getStates());
@@ -72,34 +69,7 @@ automaton::MultiInitialStateNFA Reverse::convert(const automaton::MultiInitialSt
 	return res;
 }
 
-void Reverse::Visit(void* data, const DFA& automaton) const {
-	automaton::Automaton*& out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->convert(automaton));
-}
-
-void Reverse::Visit(void* data, const NFA& automaton) const {
-	automaton::Automaton*& out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->convert(automaton));
-}
-
-void Reverse::Visit(void* data, const MultiInitialStateNFA& automaton) const {
-	automaton::Automaton*& out = *((automaton::Automaton**) data);
-	out = new automaton::Automaton(this->convert(automaton));
-}
-
-void Reverse::Visit(void*, const ExtendedNFA&) const {
-	throw exception::AlibException("Unsupported automaton type ExtendedNFA");
-}
-
-void Reverse::Visit(void*, const EpsilonNFA&) const {
-	throw exception::AlibException("Unsupported automaton type EpsilonNFA");
-}
-
-void Reverse::Visit(void*, const CompactNFA&) const {
-	throw exception::AlibException("Unsupported automaton type CompactNFA");
-}
-
-const Reverse Reverse::REVERSE;
+auto ReverseMultiInitialStateNFA = Reverse::RegistratorWrapper<automaton::MultiInitialStateNFA, automaton::MultiInitialStateNFA>(Reverse::getInstance(), Reverse::convert);
 
 } /* namespace transform */
 
diff --git a/alib2algo/src/automaton/transform/Reverse.h b/alib2algo/src/automaton/transform/Reverse.h
index de596f31a57f36796de46706a8c937e00e6532a5..337a7f647294dd82c9ed54b820bf31acf0cc5c9e 100644
--- a/alib2algo/src/automaton/transform/Reverse.h
+++ b/alib2algo/src/automaton/transform/Reverse.h
@@ -8,6 +8,7 @@
 #ifndef REVERSE_H_
 #define REVERSE_H_
 
+#include <common/multipleDispatch.hpp>
 #include <automaton/Automaton.h>
 #include <automaton/common/State.h>
 
@@ -15,10 +16,8 @@ namespace automaton {
 
 namespace transform {
 
-class Reverse : public automaton::VisitableConstFSMBase {
+class Reverse : public std::SingleDispatch<automaton::Automaton, automaton::AutomatonBase> {
 public:
-	Reverse() {}
-
 	static automaton::MultiInitialStateNFA convert(const automaton::DFA& automaton);
 	static automaton::MultiInitialStateNFA convert(const automaton::NFA& automaton);
 	static automaton::MultiInitialStateNFA convert(const automaton::MultiInitialStateNFA& automaton);
@@ -29,17 +28,11 @@ public:
 	 * @return Automaton reverse automaton
 	 */
 	static automaton::Automaton convert( const automaton::Automaton & automaton );
-private:
-	using automaton::VisitableConstFSMBase::Visit;
-
-	void Visit(void*, const DFA& automaton) const;
-	void Visit(void*, const NFA& automaton) const;
-	void Visit(void*, const MultiInitialStateNFA& automaton) const;
-	void Visit(void*, const ExtendedNFA& automaton) const;
-	void Visit(void*, const EpsilonNFA& automaton) const;
-	void Visit(void*, const CompactNFA& automaton) const;
 
-	static const Reverse REVERSE;
+	static Reverse& getInstance() {
+		static Reverse res;
+		return res;
+	}
 };
 
 } /* namespace transform */