diff --git a/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.cpp b/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.cpp
index 469aa9f185e2fd84d2e4ad4971f02471b3beb40f..1982aaa90de99cd6fb35a7a238d1070333259138 100644
--- a/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.cpp
+++ b/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.cpp
@@ -17,85 +17,8 @@ automaton::Automaton AutomataUnionCartesianProduct::unification(const automaton:
 	return dispatch(first.getData(), second.getData());
 }
 
-automaton::DFA<> AutomataUnionCartesianProduct::unification(const automaton::DFA<>& first, const automaton::DFA<>& second) {
-	if(!first.isTotal() || !second.isTotal())
-		throw exception::CommonException("Automata must be total to unify with cartesian product");
-
-	DefaultStateType q0(first.getInitialState(), second.getInitialState());
-	automaton::DFA<> res(q0);
-
-	for(const auto& a : first.getInputAlphabet())
-		res.addInputSymbol(a);
-	for(const auto& a : second.getInputAlphabet())
-		res.addInputSymbol(a);
-
-	for(const auto& p : first.getStates())
-		for(const auto& q : second.getStates())
-			res.addState(DefaultStateType(p, q));
-
-	for(const auto& p : first.getFinalStates())
-		for(const auto& q : second.getStates())
-			res.addFinalState(DefaultStateType(p, q));
-
-	for(const auto& p : first.getStates())
-		for(const auto& q : second.getFinalStates())
-			res.addFinalState(DefaultStateType(p, q));
-
-	for(const auto& state : res.getStates()) {
-		const DefaultStateType& label_p = static_cast<const DefaultStatesPairType&>(state.getData()).first;
-		const DefaultStateType& label_q = static_cast<const DefaultStatesPairType&>(state.getData()).second;
-
-		for(const auto& tp : first.getTransitionsFromState(DefaultStateType(label_p)))
-			for(const auto& tq : second.getTransitionsFromState(DefaultStateType(label_q)))
-				if(tp.first.second == tq.first.second)
-					res.addTransition(state, tp.first.second, DefaultStateType(tp.second, tq.second));
-	}
-
-	return res;
-}
-
-auto AutomataUnionCartesianProductDFA = AutomataUnionCartesianProduct::RegistratorWrapper<automaton::DFA<>, automaton::DFA<>>(AutomataUnionCartesianProduct::unification);
-
-automaton::NFA < > AutomataUnionCartesianProduct::unification(const automaton::NFA < > & first, const automaton::NFA < > & second) {
-	if(!first.isTotal() || !second.isTotal())
-		throw exception::CommonException("Automata must be total to unify with cartesian product");
-
-	DefaultStateType q0(first.getInitialState(), second.getInitialState());
-	automaton::NFA < > res(q0);
-
-	for(const auto& a : first.getInputAlphabet())
-		res.addInputSymbol(a);
-	for(const auto& a : second.getInputAlphabet())
-		res.addInputSymbol(a);
-
-	for(const auto& p : first.getStates())
-		for(const auto& q : second.getStates())
-			res.addState(DefaultStateType(p, q));
-
-	for(const auto& p : first.getFinalStates())
-		for(const auto& q : second.getStates())
-			res.addFinalState(DefaultStateType(p, q));
-
-	for(const auto& p : first.getStates())
-		for(const auto& q : second.getFinalStates())
-			res.addFinalState(DefaultStateType(p, q));
-
-	for(const auto& state : res.getStates()) {
-		const DefaultStateType& label_p = static_cast<const DefaultStatesPairType&>(state.getData()).first;
-		const DefaultStateType& label_q = static_cast<const DefaultStatesPairType&>(state.getData()).second;
-
-		for(const auto& tp : first.getTransitionsFromState(DefaultStateType(label_p)))
-			for(const auto& tq : second.getTransitionsFromState(DefaultStateType(label_q)))
-				if(tp.first.second == tq.first.second)
-					for(const auto& p : tp.second)
-						for(const auto& q : tq.second)
-							res.addTransition(state, tp.first.second, DefaultStateType(p, q));
-	}
-
-	return res;
-}
-
-auto AutomataUnionCartesianProductNFA = AutomataUnionCartesianProduct::RegistratorWrapper<automaton::NFA < > , automaton::NFA < > >(AutomataUnionCartesianProduct::unification);
+auto AutomataUnionCartesianProductDFA = AutomataUnionCartesianProduct::RegistratorWrapper<automaton::DFA < DefaultSymbolType, std::pair < DefaultStateType, DefaultStateType > >, automaton::DFA < > >(AutomataUnionCartesianProduct::unification);
+auto AutomataUnionCartesianProductNFA = AutomataUnionCartesianProduct::RegistratorWrapper<automaton::NFA < DefaultSymbolType, std::pair < DefaultStateType, DefaultStateType > >, automaton::NFA < > >(AutomataUnionCartesianProduct::unification);
 
 } /* namespace transform */
 
diff --git a/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.h b/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.h
index feba05962f8bfb9ca68642c2fd14d74f47369d5d..71b72623c173aa895590d582229f4faa7ab100f9 100644
--- a/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.h
+++ b/alib2algo/src/automaton/transform/AutomataUnionCartesianProduct.h
@@ -24,10 +24,83 @@ class AutomataUnionCartesianProduct : public std::PromotingDoubleDispatch<Automa
 public:
 	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);
+	template < class SymbolType, class StateType1, class StateType2 >
+	static automaton::NFA < SymbolType, std::pair < StateType1, StateType2 > > unification(const automaton::NFA < SymbolType, StateType1 > & first, const automaton::NFA < SymbolType, StateType2 > & second);
+	template < class SymbolType, class StateType1, class StateType2 >
+	static automaton::DFA < SymbolType, std::pair < StateType1, StateType2 > > unification(const automaton::DFA < SymbolType, StateType1 > & first, const automaton::DFA < SymbolType, StateType2 > & second);
 };
 
+template < class SymbolType, class StateType1, class StateType2 >
+automaton::DFA < SymbolType, std::pair < StateType1, StateType2 > > AutomataUnionCartesianProduct::unification(const automaton::DFA < SymbolType, StateType1 > & first, const automaton::DFA < SymbolType, StateType2 > & second) {
+	if(!first.isTotal() || !second.isTotal())
+		throw exception::CommonException("Automata must be total to unify with cartesian product");
+
+	std::pair < StateType1, StateType2 > q0 ( first.getInitialState(), second.getInitialState() );
+	automaton::DFA < SymbolType, std::pair < StateType1, StateType2 > > res ( q0 );
+
+	for(const auto& a : first.getInputAlphabet())
+		res.addInputSymbol(a);
+	for(const auto& a : second.getInputAlphabet())
+		res.addInputSymbol(a);
+
+	for(const auto& p : first.getStates())
+		for(const auto& q : second.getStates())
+			res.addState(std::make_pair(p, q));
+
+	for(const auto& p : first.getFinalStates())
+		for(const auto& q : second.getStates())
+			res.addFinalState(std::make_pair(p, q));
+
+	for(const auto& p : first.getStates())
+		for(const auto& q : second.getFinalStates())
+			res.addFinalState(std::make_pair(p, q));
+
+	for(const auto& state : res.getStates())
+		for(const auto& tp : first.getTransitionsFromState(state.first))
+			for(const auto& tq : second.getTransitionsFromState(state.second))
+				if(tp.first.second == tq.first.second)
+					res.addTransition(state, tp.first.second, std::make_pair(tp.second, tq.second));
+
+
+	return res;
+}
+
+template < class SymbolType, class StateType1, class StateType2 >
+automaton::NFA < SymbolType, std::pair < StateType1, StateType2 > > AutomataUnionCartesianProduct::unification(const automaton::NFA < SymbolType, StateType1 > & first, const automaton::NFA < SymbolType, StateType2 > & second) {
+	if(!first.isTotal() || !second.isTotal())
+		throw exception::CommonException("Automata must be total to unify with cartesian product");
+
+	std::pair < StateType1, StateType2 > q0 ( first.getInitialState(), second.getInitialState() );
+	automaton::NFA < SymbolType, std::pair < StateType1, StateType2 > > res(q0);
+
+	for(const auto& a : first.getInputAlphabet())
+		res.addInputSymbol(a);
+	for(const auto& a : second.getInputAlphabet())
+		res.addInputSymbol(a);
+
+	for(const auto& p : first.getStates())
+		for(const auto& q : second.getStates())
+			res.addState(std::make_pair(p, q));
+
+	for(const auto& p : first.getFinalStates())
+		for(const auto& q : second.getStates())
+			res.addFinalState(std::make_pair(p, q));
+
+	for(const auto& p : first.getStates())
+		for(const auto& q : second.getFinalStates())
+			res.addFinalState(std::make_pair(p, q));
+
+	for(const auto& state : res.getStates())
+		for(const auto& tp : first.getTransitionsFromState(state.first))
+			for(const auto& tq : second.getTransitionsFromState(state.second))
+				if(tp.first.second == tq.first.second)
+					for(const auto& p : tp.second)
+						for(const auto& q : tq.second)
+							res.addTransition(state, tp.first.second, std::make_pair(p, q));
+
+	return res;
+}
+
 } /* namespace transform */
 
 } /* namespace automaton */