diff --git a/alib2algo/src/automaton/transform/AutomataConcatenation.cpp b/alib2algo/src/automaton/transform/AutomataConcatenation.cpp
index 517384911eda043dbe762d8f2eaeaf11e9f3996c..14419a6a81342259edadb3eeb416d6ed2458b560 100644
--- a/alib2algo/src/automaton/transform/AutomataConcatenation.cpp
+++ b/alib2algo/src/automaton/transform/AutomataConcatenation.cpp
@@ -8,9 +8,6 @@
 #include "AutomataConcatenation.h"
 #include <label/Label.h>
 
-#define AUTOMATON_FIRST  (label::Label(1))
-#define AUTOMATON_SECOND (label::Label(2))
-
 namespace automaton {
 
 namespace transform {
@@ -19,94 +16,8 @@ automaton::Automaton AutomataConcatenation::concatenation(const automaton::Autom
 	return dispatch(first.getData(), second.getData());
 }
 
-automaton::NFA < > AutomataConcatenation::concatenation(const automaton::NFA < > & first, const automaton::NFA < > & second) {
-	label::Label q01q02(first.getInitialState(), second.getInitialState());
-	automaton::NFA < > res(label::Label(AUTOMATON_FIRST, first.getInitialState()));
-
-	for(const auto& q : first.getStates())
-		res.addState(label::Label(AUTOMATON_FIRST, q));
-	for(const auto& q : second.getStates())
-		res.addState(label::Label(AUTOMATON_SECOND, q));
-	res.addState(q01q02);
-
-	for(const auto& symbol : first.getInputAlphabet())
-		res.addInputSymbol(symbol);
-	for(const auto& symbol : second.getInputAlphabet())
-		res.addInputSymbol(symbol);
-
-	if(first.getFinalStates().count(first.getInitialState()) > 0)
-		res.setInitialState(q01q02);
-
-	for(const auto& t : first.getTransitions()) {
-		for(const auto& q : t.second) {
-			res.addTransition(label::Label(AUTOMATON_FIRST, t.first.first), t.first.second, label::Label(AUTOMATON_FIRST, q));
-
-			if(first.getFinalStates().count(q) > 0)
-				res.addTransition(label::Label(AUTOMATON_FIRST, t.first.first), t.first.second, label::Label(AUTOMATON_SECOND, second.getInitialState()));
-		}
-	}
-	for(const auto& t : second.getTransitions())
-		for(const auto& q : t.second)
-			res.addTransition(label::Label(AUTOMATON_SECOND, t.first.first), t.first.second, label::Label(AUTOMATON_SECOND, q));
-
-	for(const auto& t : first.getTransitionsFromState(first.getInitialState()))
-		for(const auto& q : t.second)
-			res.addTransition(q01q02, t.first.second, label::Label(AUTOMATON_FIRST, q));
-	for(const auto& t : second.getTransitionsFromState(second.getInitialState()))
-		for(const auto& q : t.second)
-			res.addTransition(q01q02, t.first.second, label::Label(AUTOMATON_SECOND, q));
-
-	for(const auto& q : second.getFinalStates())
-		res.addFinalState(label::Label(AUTOMATON_SECOND, q));
-	if(first.getFinalStates().count(first.getInitialState()) > 0)
-		res.addFinalState(q01q02);
-
-	return res;
-}
-
 auto AutomataConcatenationNFA = AutomataConcatenation::RegistratorWrapper<automaton::NFA < > , automaton::NFA < > >(AutomataConcatenation::concatenation);
-
-automaton::NFA < > AutomataConcatenation::concatenation(const automaton::DFA<>& first, const automaton::DFA<>& second) {
-	label::Label q01q02(first.getInitialState(), second.getInitialState());
-	automaton::NFA < > res(label::Label(AUTOMATON_FIRST, first.getInitialState()));
-
-	for(const auto& q : first.getStates())
-		res.addState(label::Label(AUTOMATON_FIRST, q));
-	for(const auto& q : second.getStates())
-		res.addState(label::Label(AUTOMATON_SECOND, q));
-	res.addState(q01q02);
-
-	for(const auto& symbol : first.getInputAlphabet())
-		res.addInputSymbol(symbol);
-	for(const auto& symbol : second.getInputAlphabet())
-		res.addInputSymbol(symbol);
-
-	if(first.getFinalStates().count(first.getInitialState()) > 0)
-		res.setInitialState(q01q02);
-
-	for(const auto& t : first.getTransitions()) {
-		res.addTransition(label::Label(AUTOMATON_FIRST, t.first.first), t.first.second, label::Label(AUTOMATON_FIRST, t.second));
-
-		if(first.getFinalStates().count(t.second) > 0)
-			res.addTransition(label::Label(AUTOMATON_FIRST, t.first.first), t.first.second, label::Label(AUTOMATON_SECOND, second.getInitialState()));
-	}
-	for(const auto& t : second.getTransitions())
-		res.addTransition(label::Label(AUTOMATON_SECOND, t.first.first), t.first.second, label::Label(AUTOMATON_SECOND, t.second));
-
-	for(const auto& t : first.getTransitionsFromState(first.getInitialState()))
-		res.addTransition(q01q02, t.first.second, label::Label(AUTOMATON_FIRST, t.second));
-	for(const auto& t : second.getTransitionsFromState(second.getInitialState()))
-		res.addTransition(q01q02, t.first.second, label::Label(AUTOMATON_SECOND, t.second));
-
-	for(const auto& q : second.getFinalStates())
-		res.addFinalState(label::Label(AUTOMATON_SECOND, q));
-	if(first.getFinalStates().count(first.getInitialState()) > 0)
-		res.addFinalState(q01q02);
-
-	return res;
-}
-
-auto AutomataConcatenationDFA = AutomataConcatenation::RegistratorWrapper<automaton::NFA < > , automaton::DFA<>>(AutomataConcatenation::concatenation);
+auto AutomataConcatenationDFA = AutomataConcatenation::RegistratorWrapper<automaton::NFA < > , automaton::DFA < > >(AutomataConcatenation::concatenation);
 
 } /* namespace transform */
 
diff --git a/alib2algo/src/automaton/transform/AutomataConcatenation.h b/alib2algo/src/automaton/transform/AutomataConcatenation.h
index 49640f6a6ef6f62a3ecbd7f98de7face3de8e5bc..faf1924ee0ef91a7e58081086f18dd672499c70e 100644
--- a/alib2algo/src/automaton/transform/AutomataConcatenation.h
+++ b/alib2algo/src/automaton/transform/AutomataConcatenation.h
@@ -24,10 +24,105 @@ class AutomataConcatenation : public std::PromotingDoubleDispatch<AutomataConcat
 public:
 	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);
+	template < class SymbolType, class StateType >
+	static automaton::NFA < SymbolType, StateType > concatenation(const automaton::DFA < SymbolType, StateType > & first, const automaton::DFA < SymbolType, StateType > & second);
+	template < class SymbolType, class StateType >
+	static automaton::NFA < SymbolType, StateType > concatenation(const automaton::NFA < SymbolType, StateType > & first, const automaton::NFA < SymbolType, StateType > & second);
 };
 
+template < class SymbolType, class StateType >
+automaton::NFA < SymbolType, StateType > AutomataConcatenation::concatenation(const automaton::NFA < SymbolType, StateType > & first, const automaton::NFA < SymbolType, StateType > & second) {
+	static StateType firstDefault ( 1 );
+	static StateType secondDefault ( 2 );
+
+	label::Label q01q02(first.getInitialState(), second.getInitialState());
+	automaton::NFA < SymbolType, StateType > res(label::Label(firstDefault, first.getInitialState()));
+
+	for(const auto& q : first.getStates())
+		res.addState(label::Label(firstDefault, q));
+	for(const auto& q : second.getStates())
+		res.addState(label::Label(secondDefault, q));
+	res.addState(q01q02);
+
+	for(const auto& symbol : first.getInputAlphabet())
+		res.addInputSymbol(symbol);
+	for(const auto& symbol : second.getInputAlphabet())
+		res.addInputSymbol(symbol);
+
+	if(first.getFinalStates().count(first.getInitialState()) > 0)
+		res.setInitialState(q01q02);
+
+	for(const auto& t : first.getTransitions()) {
+		for(const auto& q : t.second) {
+			res.addTransition(label::Label(firstDefault, t.first.first), t.first.second, label::Label(firstDefault, q));
+
+			if(first.getFinalStates().count(q) > 0)
+				res.addTransition(label::Label(firstDefault, t.first.first), t.first.second, label::Label(secondDefault, second.getInitialState()));
+		}
+	}
+	for(const auto& t : second.getTransitions())
+		for(const auto& q : t.second)
+			res.addTransition(label::Label(secondDefault, t.first.first), t.first.second, label::Label(secondDefault, q));
+
+	for(const auto& t : first.getTransitionsFromState(first.getInitialState()))
+		for(const auto& q : t.second)
+			res.addTransition(q01q02, t.first.second, label::Label(firstDefault, q));
+	for(const auto& t : second.getTransitionsFromState(second.getInitialState()))
+		for(const auto& q : t.second)
+			res.addTransition(q01q02, t.first.second, label::Label(secondDefault, q));
+
+	for(const auto& q : second.getFinalStates())
+		res.addFinalState(label::Label(secondDefault, q));
+	if(first.getFinalStates().count(first.getInitialState()) > 0)
+		res.addFinalState(q01q02);
+
+	return res;
+}
+
+template < class SymbolType, class StateType >
+automaton::NFA < SymbolType, StateType > AutomataConcatenation::concatenation(const automaton::DFA < SymbolType, StateType > & first, const automaton::DFA < SymbolType, StateType > & second) {
+	static StateType firstDefault ( 1 );
+	static StateType secondDefault ( 2 );
+
+	label::Label q01q02(first.getInitialState(), second.getInitialState());
+	automaton::NFA < SymbolType, StateType > res(label::Label(firstDefault, first.getInitialState()));
+
+	for(const auto& q : first.getStates())
+		res.addState(label::Label(firstDefault, q));
+	for(const auto& q : second.getStates())
+		res.addState(label::Label(secondDefault, q));
+	res.addState(q01q02);
+
+	for(const auto& symbol : first.getInputAlphabet())
+		res.addInputSymbol(symbol);
+	for(const auto& symbol : second.getInputAlphabet())
+		res.addInputSymbol(symbol);
+
+	if(first.getFinalStates().count(first.getInitialState()) > 0)
+		res.setInitialState(q01q02);
+
+	for(const auto& t : first.getTransitions()) {
+		res.addTransition(label::Label(firstDefault, t.first.first), t.first.second, label::Label(firstDefault, t.second));
+
+		if(first.getFinalStates().count(t.second) > 0)
+			res.addTransition(label::Label(firstDefault, t.first.first), t.first.second, label::Label(secondDefault, second.getInitialState()));
+	}
+	for(const auto& t : second.getTransitions())
+		res.addTransition(label::Label(secondDefault, t.first.first), t.first.second, label::Label(secondDefault, t.second));
+
+	for(const auto& t : first.getTransitionsFromState(first.getInitialState()))
+		res.addTransition(q01q02, t.first.second, label::Label(firstDefault, t.second));
+	for(const auto& t : second.getTransitionsFromState(second.getInitialState()))
+		res.addTransition(q01q02, t.first.second, label::Label(secondDefault, t.second));
+
+	for(const auto& q : second.getFinalStates())
+		res.addFinalState(label::Label(secondDefault, q));
+	if(first.getFinalStates().count(first.getInitialState()) > 0)
+		res.addFinalState(q01q02);
+
+	return res;
+}
+
 } /* namespace transform */
 
 } /* namespace automaton */
diff --git a/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.cpp b/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.cpp
index 508b5b5f4177f163e274ced02773242a34fdf28a..6b1ea09622096cb24fa3d2d6bcfd5fcd2407c70c 100644
--- a/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.cpp
+++ b/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.cpp
@@ -8,9 +8,6 @@
 #include "AutomataConcatenationEpsilonTransition.h"
 #include <label/Label.h>
 
-#define AUTOMATON_FIRST  (label::Label(1))
-#define AUTOMATON_SECOND (label::Label(2))
-
 namespace automaton {
 
 namespace transform {
@@ -19,98 +16,8 @@ automaton::Automaton AutomataConcatenationEpsilonTransition::concatenation(const
 	return dispatch(first.getData(), second.getData());
 }
 
-automaton::EpsilonNFA < > AutomataConcatenationEpsilonTransition::concatenation(const automaton::DFA<>& first, const automaton::DFA<>& second) {
-	automaton::EpsilonNFA < > res(label::Label(AUTOMATON_FIRST, first.getInitialState()));
-
-	for(const auto& symbol : first.getInputAlphabet())
-		res.addInputSymbol(symbol);
-	for(const auto& symbol : second.getInputAlphabet())
-		res.addInputSymbol(symbol);
-
-	for(const auto& q : first.getStates())
-		res.addState(label::Label(AUTOMATON_FIRST, q));
-	for(const auto& q : second.getStates())
-		res.addState(label::Label(AUTOMATON_SECOND, q));
-
-	for(const auto& q : second.getFinalStates())
-		res.addFinalState(label::Label(AUTOMATON_SECOND, q));
-
-	for(const auto& t : first.getTransitions())
-		res.addTransition(label::Label(AUTOMATON_FIRST, t.first.first), t.first.second, label::Label(AUTOMATON_FIRST, t.second));
-
-	for(const auto& t : second.getTransitions())
-		res.addTransition(label::Label(AUTOMATON_SECOND, t.first.first), t.first.second, label::Label(AUTOMATON_SECOND, t.second));
-
-	for(const auto& q : first.getFinalStates())
-		res.addTransition(label::Label(AUTOMATON_FIRST, q), label::Label(AUTOMATON_SECOND, second.getInitialState()));
-
-	return res;
-}
-
-auto AutomataConcatenationEpsilonTransitionDFA = AutomataConcatenationEpsilonTransition::RegistratorWrapper<automaton::EpsilonNFA < >, automaton::DFA<>>(AutomataConcatenationEpsilonTransition::concatenation);
-
-automaton::EpsilonNFA < > AutomataConcatenationEpsilonTransition::concatenation(const automaton::NFA < > & first, const automaton::NFA < > & second) {
-	automaton::EpsilonNFA < > res(label::Label(AUTOMATON_FIRST, first.getInitialState()));
-
-	for(const auto& symbol : first.getInputAlphabet())
-		res.addInputSymbol(symbol);
-	for(const auto& symbol : second.getInputAlphabet())
-		res.addInputSymbol(symbol);
-
-	for(const auto& q : first.getStates())
-		res.addState(label::Label(AUTOMATON_FIRST, q));
-	for(const auto& q : second.getStates())
-		res.addState(label::Label(AUTOMATON_SECOND, q));
-
-	for(const auto& q : second.getFinalStates())
-		res.addFinalState(label::Label(AUTOMATON_SECOND, q));
-
-	for(const auto& t : first.getTransitions())
-		for(const auto& q : t.second)
-			res.addTransition(label::Label(AUTOMATON_FIRST, t.first.first), t.first.second, label::Label(AUTOMATON_FIRST, q));
-
-	for(const auto& t : second.getTransitions())
-		for(const auto& q : t.second)
-			res.addTransition(label::Label(AUTOMATON_SECOND, t.first.first), t.first.second, label::Label(AUTOMATON_SECOND, q));
-
-	for(const auto& q : first.getFinalStates())
-		res.addTransition(label::Label(AUTOMATON_FIRST, q), label::Label(AUTOMATON_SECOND, second.getInitialState()));
-
-	return res;
-}
-
+auto AutomataConcatenationEpsilonTransitionDFA = AutomataConcatenationEpsilonTransition::RegistratorWrapper<automaton::EpsilonNFA < >, automaton::DFA < > >(AutomataConcatenationEpsilonTransition::concatenation);
 auto AutomataConcatenationEpsilonTransitionNFA = AutomataConcatenationEpsilonTransition::RegistratorWrapper<automaton::EpsilonNFA < >, automaton::NFA < > >(AutomataConcatenationEpsilonTransition::concatenation);
-
-automaton::EpsilonNFA < > AutomataConcatenationEpsilonTransition::concatenation(const automaton::EpsilonNFA < > & first, const automaton::EpsilonNFA < > & second) {
-	automaton::EpsilonNFA < > res(label::Label(AUTOMATON_FIRST, first.getInitialState()));
-
-	for(const auto& symbol : first.getInputAlphabet())
-		res.addInputSymbol(symbol);
-	for(const auto& symbol : second.getInputAlphabet())
-		res.addInputSymbol(symbol);
-
-	for(const auto& q : first.getStates())
-		res.addState(label::Label(AUTOMATON_FIRST, q));
-	for(const auto& q : second.getStates())
-		res.addState(label::Label(AUTOMATON_SECOND, q));
-
-	for(const auto& q : second.getFinalStates())
-		res.addFinalState(label::Label(AUTOMATON_SECOND, q));
-
-	for(const auto& t : first.getTransitions())
-		for(const auto& q : t.second)
-			res.addTransition(label::Label(AUTOMATON_FIRST, t.first.first), t.first.second, label::Label(AUTOMATON_FIRST, q));
-
-	for(const auto& t : second.getTransitions())
-		for(const auto& q : t.second)
-			res.addTransition(label::Label(AUTOMATON_SECOND, t.first.first), t.first.second, label::Label(AUTOMATON_SECOND, q));
-
-	for(const auto& q : first.getFinalStates())
-		res.addTransition(label::Label(AUTOMATON_FIRST, q), label::Label(AUTOMATON_SECOND, second.getInitialState()));
-
-	return res;
-}
-
 auto AutomataConcatenationEpsilonTransitionEpsilonNFA = AutomataConcatenationEpsilonTransition::RegistratorWrapper<automaton::EpsilonNFA < > , automaton::EpsilonNFA < > >(AutomataConcatenationEpsilonTransition::concatenation);
 
 } /* namespace transform */
diff --git a/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.h b/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.h
index f7065803f0600b33c4af95219927d04fcd06901a..fb56b4a46bcedcce89ef3c4acfdc33151d9f2c21 100644
--- a/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.h
+++ b/alib2algo/src/automaton/transform/AutomataConcatenationEpsilonTransition.h
@@ -24,11 +24,114 @@ class AutomataConcatenationEpsilonTransition : public std::PromotingDoubleDispat
 public:
 	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);
+	template < class SymbolType, class EpsilonType = DefaultEpsilonType, class StateType >
+	static automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > concatenation(const automaton::DFA < SymbolType, StateType > & first, const automaton::DFA < SymbolType, StateType > & second);
+	template < class SymbolType, class EpsilonType = DefaultEpsilonType, class StateType >
+	static automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > concatenation(const automaton::NFA < SymbolType, StateType > & first, const automaton::NFA < SymbolType, StateType > & second);
+	template < class SymbolType, class EpsilonType, class StateType >
+	static automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > concatenation(const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & first, const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & second);
 };
 
+template < class SymbolType, class EpsilonType, class StateType >
+automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > AutomataConcatenationEpsilonTransition::concatenation(const automaton::DFA < SymbolType, StateType > & first, const automaton::DFA < SymbolType, StateType > & second) {
+	static StateType firstDefault ( 1 );
+	static StateType secondDefault ( 2 );
+
+	automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > res(label::Label(firstDefault, first.getInitialState()));
+
+	for(const auto& symbol : first.getInputAlphabet())
+		res.addInputSymbol(symbol);
+	for(const auto& symbol : second.getInputAlphabet())
+		res.addInputSymbol(symbol);
+
+	for(const auto& q : first.getStates())
+		res.addState(label::Label(firstDefault, q));
+	for(const auto& q : second.getStates())
+		res.addState(label::Label(secondDefault, q));
+
+	for(const auto& q : second.getFinalStates())
+		res.addFinalState(label::Label(secondDefault, q));
+
+	for(const auto& t : first.getTransitions())
+		res.addTransition(label::Label(firstDefault, t.first.first), t.first.second, label::Label(firstDefault, t.second));
+
+	for(const auto& t : second.getTransitions())
+		res.addTransition(label::Label(secondDefault, t.first.first), t.first.second, label::Label(secondDefault, t.second));
+
+	for(const auto& q : first.getFinalStates())
+		res.addTransition(label::Label(firstDefault, q), label::Label(secondDefault, second.getInitialState()));
+
+	return res;
+}
+
+template < class SymbolType, class EpsilonType, class StateType >
+automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > AutomataConcatenationEpsilonTransition::concatenation(const automaton::NFA < SymbolType, StateType > & first, const automaton::NFA < SymbolType, StateType > & second) {
+	static StateType firstDefault ( 1 );
+	static StateType secondDefault ( 2 );
+
+	automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > res(label::Label(firstDefault, first.getInitialState()));
+
+	for(const auto& symbol : first.getInputAlphabet())
+		res.addInputSymbol(symbol);
+	for(const auto& symbol : second.getInputAlphabet())
+		res.addInputSymbol(symbol);
+
+	for(const auto& q : first.getStates())
+		res.addState(label::Label(firstDefault, q));
+	for(const auto& q : second.getStates())
+		res.addState(label::Label(secondDefault, q));
+
+	for(const auto& q : second.getFinalStates())
+		res.addFinalState(label::Label(secondDefault, q));
+
+	for(const auto& t : first.getTransitions())
+		for(const auto& q : t.second)
+			res.addTransition(label::Label(firstDefault, t.first.first), t.first.second, label::Label(firstDefault, q));
+
+	for(const auto& t : second.getTransitions())
+		for(const auto& q : t.second)
+			res.addTransition(label::Label(secondDefault, t.first.first), t.first.second, label::Label(secondDefault, q));
+
+	for(const auto& q : first.getFinalStates())
+		res.addTransition(label::Label(firstDefault, q), label::Label(secondDefault, second.getInitialState()));
+
+	return res;
+}
+
+template < class SymbolType, class EpsilonType, class StateType >
+automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > AutomataConcatenationEpsilonTransition::concatenation(const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & first, const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & second) {
+	static StateType firstDefault ( 1 );
+	static StateType secondDefault ( 2 );
+
+	automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > res(label::Label(firstDefault, first.getInitialState()));
+
+	for(const auto& symbol : first.getInputAlphabet())
+		res.addInputSymbol(symbol);
+	for(const auto& symbol : second.getInputAlphabet())
+		res.addInputSymbol(symbol);
+
+	for(const auto& q : first.getStates())
+		res.addState(label::Label(firstDefault, q));
+	for(const auto& q : second.getStates())
+		res.addState(label::Label(secondDefault, q));
+
+	for(const auto& q : second.getFinalStates())
+		res.addFinalState(label::Label(secondDefault, q));
+
+	for(const auto& t : first.getTransitions())
+		for(const auto& q : t.second)
+			res.addTransition(label::Label(firstDefault, t.first.first), t.first.second, label::Label(firstDefault, q));
+
+	for(const auto& t : second.getTransitions())
+		for(const auto& q : t.second)
+			res.addTransition(label::Label(secondDefault, t.first.first), t.first.second, label::Label(secondDefault, q));
+
+	for(const auto& q : first.getFinalStates())
+		res.addTransition(label::Label(firstDefault, q), label::Label(secondDefault, second.getInitialState()));
+
+	return res;
+}
+
 } /* namespace transform */
 
 } /* namespace automaton */
diff --git a/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.cpp b/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.cpp
index 6f886e6732187cb2400ef8dbba4cde4513b80ae2..bba6f9ceec573818a32858b3b347ecae3eb763b4 100644
--- a/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.cpp
+++ b/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.cpp
@@ -9,9 +9,6 @@
 #include <label/InitialStateLabel.h>
 #include <common/createUnique.hpp>
 
-#define AUTOMATON_FIRST  (label::Label(1))
-#define AUTOMATON_SECOND (label::Label(2))
-
 namespace automaton {
 
 namespace transform {
@@ -20,120 +17,9 @@ automaton::Automaton AutomataUnionEpsilonTransition::unification(const automaton
 	return dispatch(first.getData(), second.getData());
 }
 
-automaton::EpsilonNFA < > AutomataUnionEpsilonTransition::unification(const automaton::EpsilonNFA < > & first, const automaton::EpsilonNFA < > & second) {
-	std::set<label::Label> states;
-	for(const auto& q : first.getStates())
-		states.insert(label::Label(AUTOMATON_FIRST, q));
-	for(const auto& q : second.getStates())
-		states.insert(label::Label(AUTOMATON_SECOND, q));
-
-	label::Label q0 = common::createUnique(label::InitialStateLabel::instance < label::Label > ( ), states);
-	automaton::EpsilonNFA < > res(q0);
-
-	for(const auto& a : first.getInputAlphabet())
-		res.addInputSymbol(a);
-	for(const auto& a : second.getInputAlphabet())
-		res.addInputSymbol(a);
-
-	for(const auto& q : states)
-		res.addState(q);
-
-	for(const auto& q : first.getFinalStates())
-		res.addFinalState(label::Label(AUTOMATON_FIRST, q));
-	for(const auto& q : second.getFinalStates())
-		res.addFinalState(label::Label(AUTOMATON_SECOND, q));
-
-	res.addTransition(q0, label::Label(AUTOMATON_FIRST, first.getInitialState()));
-	res.addTransition(q0, label::Label(AUTOMATON_SECOND, second.getInitialState()));
-
-	for(const auto& t : first.getTransitions())
-		for(const auto& q : t.second)
-			res.addTransition(label::Label(AUTOMATON_FIRST, t.first.first), t.first.second, label::Label(AUTOMATON_FIRST, q));
-
-	for(const auto& t : second.getTransitions())
-		for(const auto& q : t.second)
-			res.addTransition(label::Label(AUTOMATON_SECOND, t.first.first), t.first.second, label::Label(AUTOMATON_SECOND, q));
-
-	return res;
-}
-
 auto AutomataUnionEpsilonTransitionEpsilonNFA = AutomataUnionEpsilonTransition::RegistratorWrapper<automaton::EpsilonNFA < >, automaton::EpsilonNFA < > >(AutomataUnionEpsilonTransition::unification);
-
-automaton::EpsilonNFA < > AutomataUnionEpsilonTransition::unification(const automaton::NFA < > & first, const automaton::NFA < > & second) {
-	std::set<label::Label> states;
-	for(const auto& q : first.getStates())
-		states.insert(label::Label(AUTOMATON_FIRST, q));
-	for(const auto& q : second.getStates())
-		states.insert(label::Label(AUTOMATON_SECOND, q));
-
-	label::Label q0 = common::createUnique(label::InitialStateLabel::instance < label::Label > ( ), states);
-	automaton::EpsilonNFA < > res(q0);
-
-	for(const auto& a : first.getInputAlphabet())
-		res.addInputSymbol(a);
-	for(const auto& a : second.getInputAlphabet())
-		res.addInputSymbol(a);
-
-	for(const auto& q : states)
-		res.addState(q);
-
-	for(const auto& q : first.getFinalStates())
-		res.addFinalState(label::Label(AUTOMATON_FIRST, q));
-	for(const auto& q : second.getFinalStates())
-		res.addFinalState(label::Label(AUTOMATON_SECOND, q));
-
-	res.addTransition(q0, label::Label(AUTOMATON_FIRST, first.getInitialState()));
-	res.addTransition(q0, label::Label(AUTOMATON_SECOND, second.getInitialState()));
-
-	for(const auto& t : first.getTransitions())
-		for(const auto& q : t.second)
-			res.addTransition(label::Label(AUTOMATON_FIRST, t.first.first), t.first.second, label::Label(AUTOMATON_FIRST, q));
-
-	for(const auto& t : second.getTransitions())
-		for(const auto& q : t.second)
-			res.addTransition(label::Label(AUTOMATON_SECOND, t.first.first), t.first.second, label::Label(AUTOMATON_SECOND, q));
-
-	return res;
-}
-
 auto AutomataUnionEpsilonTransitionNFA = AutomataUnionEpsilonTransition::RegistratorWrapper<automaton::EpsilonNFA < >, automaton::NFA < > >(AutomataUnionEpsilonTransition::unification);
-
-automaton::EpsilonNFA < > AutomataUnionEpsilonTransition::unification(const automaton::DFA<>& first, const automaton::DFA<>& second) {
-	std::set<label::Label> states;
-	for(const auto& q : first.getStates())
-		states.insert(label::Label(AUTOMATON_FIRST, q));
-	for(const auto& q : second.getStates())
-		states.insert(label::Label(AUTOMATON_SECOND, q));
-
-	label::Label q0 = common::createUnique(label::InitialStateLabel::instance < label::Label > ( ), states);
-	automaton::EpsilonNFA < > res(q0);
-
-	for(const auto& a : first.getInputAlphabet())
-		res.addInputSymbol(a);
-	for(const auto& a : second.getInputAlphabet())
-		res.addInputSymbol(a);
-
-	for(const auto& q : states)
-		res.addState(q);
-
-	for(const auto& q : first.getFinalStates())
-		res.addFinalState(label::Label(AUTOMATON_FIRST, q));
-	for(const auto& q : second.getFinalStates())
-		res.addFinalState(label::Label(AUTOMATON_SECOND, q));
-
-	res.addTransition(q0, label::Label(AUTOMATON_FIRST, first.getInitialState()));
-	res.addTransition(q0, label::Label(AUTOMATON_SECOND, second.getInitialState()));
-
-	for(const auto& t : first.getTransitions())
-		res.addTransition(label::Label(AUTOMATON_FIRST, t.first.first), t.first.second, label::Label(AUTOMATON_FIRST, t.second));
-
-	for(const auto& t : second.getTransitions())
-		res.addTransition(label::Label(AUTOMATON_SECOND, t.first.first), t.first.second, label::Label(AUTOMATON_SECOND, t.second));
-
-	return res;
-}
-
-auto AutomataUnionEpsilonTransitionDFA = AutomataUnionEpsilonTransition::RegistratorWrapper<automaton::EpsilonNFA < >, automaton::DFA<>>(AutomataUnionEpsilonTransition::unification);
+auto AutomataUnionEpsilonTransitionDFA = AutomataUnionEpsilonTransition::RegistratorWrapper<automaton::EpsilonNFA < >, automaton::DFA < > >(AutomataUnionEpsilonTransition::unification);
 
 } /* namespace transform */
 
diff --git a/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.h b/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.h
index b70d21fe1d3b787f6b15e5e16ef43fdd8fb79df4..372eea4b9b96f947d19ebe9fe37b9fa16f6caf41 100644
--- a/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.h
+++ b/alib2algo/src/automaton/transform/AutomataUnionEpsilonTransition.h
@@ -24,12 +24,136 @@ class AutomataUnionEpsilonTransition : public std::PromotingDoubleDispatch<Autom
 public:
 	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);
+	template < class SymbolType, class EpsilonType, class StateType >
+	static automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > unification(const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & first, const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & second);
+	template < class SymbolType, class EpsilonType = DefaultEpsilonType, class StateType >
+	static automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > unification(const automaton::NFA < SymbolType, StateType > & first, const automaton::NFA < SymbolType, StateType > & second);
+	template < class SymbolType, class EpsilonType = DefaultEpsilonType, class StateType >
+	static automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > unification(const automaton::DFA < SymbolType, StateType > & first, const automaton::DFA < SymbolType, StateType > & second);
 
 };
 
+template < class SymbolType, class EpsilonType, class StateType >
+automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > AutomataUnionEpsilonTransition::unification(const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & first, const automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > & second) {
+	static StateType firstDefault ( 1 );
+	static StateType secondDefault ( 2 );
+
+	std::set<StateType> states;
+	for(const auto& q : first.getStates())
+		states.insert(StateType(firstDefault, q));
+	for(const auto& q : second.getStates())
+		states.insert(StateType(secondDefault, q));
+
+	StateType q0 = common::createUnique(label::InitialStateLabel::instance < StateType > ( ), states);
+	automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > res(q0);
+
+	for(const auto& a : first.getInputAlphabet())
+		res.addInputSymbol(a);
+	for(const auto& a : second.getInputAlphabet())
+		res.addInputSymbol(a);
+
+	for(const auto& q : states)
+		res.addState(q);
+
+	for(const auto& q : first.getFinalStates())
+		res.addFinalState(StateType(firstDefault, q));
+	for(const auto& q : second.getFinalStates())
+		res.addFinalState(StateType(secondDefault, q));
+
+	res.addTransition(q0, StateType(firstDefault, first.getInitialState()));
+	res.addTransition(q0, StateType(secondDefault, second.getInitialState()));
+
+	for(const auto& t : first.getTransitions())
+		for(const auto& q : t.second)
+			res.addTransition(StateType(firstDefault, t.first.first), t.first.second, StateType(firstDefault, q));
+
+	for(const auto& t : second.getTransitions())
+		for(const auto& q : t.second)
+			res.addTransition(StateType(secondDefault, t.first.first), t.first.second, StateType(secondDefault, q));
+
+	return res;
+}
+
+template < class SymbolType, class EpsilonType, class StateType >
+automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > AutomataUnionEpsilonTransition::unification(const automaton::NFA < SymbolType, StateType > & first, const automaton::NFA < SymbolType, StateType > & second) {
+	static StateType firstDefault ( 1 );
+	static StateType secondDefault ( 2 );
+
+	std::set<StateType> states;
+	for(const auto& q : first.getStates())
+		states.insert(StateType(firstDefault, q));
+	for(const auto& q : second.getStates())
+		states.insert(StateType(secondDefault, q));
+
+	StateType q0 = common::createUnique(label::InitialStateLabel::instance < StateType > ( ), states);
+	automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > res(q0);
+
+	for(const auto& a : first.getInputAlphabet())
+		res.addInputSymbol(a);
+	for(const auto& a : second.getInputAlphabet())
+		res.addInputSymbol(a);
+
+	for(const auto& q : states)
+		res.addState(q);
+
+	for(const auto& q : first.getFinalStates())
+		res.addFinalState(StateType(firstDefault, q));
+	for(const auto& q : second.getFinalStates())
+		res.addFinalState(StateType(secondDefault, q));
+
+	res.addTransition(q0, StateType(firstDefault, first.getInitialState()));
+	res.addTransition(q0, StateType(secondDefault, second.getInitialState()));
+
+	for(const auto& t : first.getTransitions())
+		for(const auto& q : t.second)
+			res.addTransition(StateType(firstDefault, t.first.first), t.first.second, StateType(firstDefault, q));
+
+	for(const auto& t : second.getTransitions())
+		for(const auto& q : t.second)
+			res.addTransition(StateType(secondDefault, t.first.first), t.first.second, StateType(secondDefault, q));
+
+	return res;
+}
+
+template < class SymbolType, class EpsilonType, class StateType >
+automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > AutomataUnionEpsilonTransition::unification(const automaton::DFA< SymbolType, StateType > & first, const automaton::DFA < SymbolType, StateType > & second) {
+	static StateType firstDefault ( 1 );
+	static StateType secondDefault ( 2 );
+
+	std::set<StateType> states;
+	for(const auto& q : first.getStates())
+		states.insert(StateType(firstDefault, q));
+	for(const auto& q : second.getStates())
+		states.insert(StateType(secondDefault, q));
+
+	StateType q0 = common::createUnique(label::InitialStateLabel::instance < StateType > ( ), states);
+	automaton::EpsilonNFA < SymbolType, EpsilonType, StateType > res(q0);
+
+	for(const auto& a : first.getInputAlphabet())
+		res.addInputSymbol(a);
+	for(const auto& a : second.getInputAlphabet())
+		res.addInputSymbol(a);
+
+	for(const auto& q : states)
+		res.addState(q);
+
+	for(const auto& q : first.getFinalStates())
+		res.addFinalState(StateType(firstDefault, q));
+	for(const auto& q : second.getFinalStates())
+		res.addFinalState(StateType(secondDefault, q));
+
+	res.addTransition(q0, StateType(firstDefault, first.getInitialState()));
+	res.addTransition(q0, StateType(secondDefault, second.getInitialState()));
+
+	for(const auto& t : first.getTransitions())
+		res.addTransition(StateType(firstDefault, t.first.first), t.first.second, StateType(firstDefault, t.second));
+
+	for(const auto& t : second.getTransitions())
+		res.addTransition(StateType(secondDefault, t.first.first), t.first.second, StateType(secondDefault, t.second));
+
+	return res;
+}
+
 } /* namespace transform */
 
 } /* namespace automaton */