From 70011a43eb737ee099737a3f8b05bee47701b771 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Mon, 5 Sep 2016 19:07:45 +0200
Subject: [PATCH] unify basic dispatch algorithms

---
 alib2algo/src/graph/traverse/Bfs.cpp       |   8 +-
 alib2algo/src/graph/traverse/Dfs.cpp       |   8 +-
 alib2common/src/core/multipleDispatch.hpp  | 237 ++++-----------------
 alib2common/test-src/core/DispatchTest.cpp |   2 +-
 4 files changed, 45 insertions(+), 210 deletions(-)

diff --git a/alib2algo/src/graph/traverse/Bfs.cpp b/alib2algo/src/graph/traverse/Bfs.cpp
index a57e332ab9..974e0c7024 100644
--- a/alib2algo/src/graph/traverse/Bfs.cpp
+++ b/alib2algo/src/graph/traverse/Bfs.cpp
@@ -77,25 +77,25 @@ void Bfs::bfs(const DirectedGraph &graph, const Node &start, Bfs::Function func)
 	bfs_impl(graph, start, func);
 }
 
-auto BfsDirectedGraph1 = Bfs::SingleDispatch<Bfs, void, const graph::GraphBase &, const Node&, Bfs::Function>::RegistratorWrapper<void, graph::DirectedGraph>(Bfs::bfs);
+auto BfsDirectedGraph1 = std::SingleDispatch<Bfs, void, const graph::GraphBase &, const Node&, Bfs::Function>::RegistratorWrapper<void, graph::DirectedGraph>(Bfs::bfs);
 
 void Bfs::bfs(const DirectedGraph &graph, const Node &start, Bfs::FunctionExt func) {
 	bfs2_impl(graph, start, func);
 }
 
-auto BfsDirectedGraph2 = Bfs::SingleDispatch<Bfs, void, const graph::GraphBase &, const Node&, Bfs::FunctionExt>::RegistratorWrapper<void, graph::DirectedGraph>(Bfs::bfs);
+auto BfsDirectedGraph2 = std::SingleDispatch<Bfs, void, const graph::GraphBase &, const Node&, Bfs::FunctionExt>::RegistratorWrapper<void, graph::DirectedGraph>(Bfs::bfs);
 
 void Bfs::bfs(const UndirectedGraph &graph, const Node &start, Bfs::Function func) {
 	bfs_impl(graph, start, func);
 }
 
-auto BfsUndirectedGraph1 = Bfs::SingleDispatch<Bfs, void, const graph::GraphBase &, const Node&, Bfs::Function>::RegistratorWrapper<void, graph::UndirectedGraph>(Bfs::bfs);
+auto BfsUndirectedGraph1 = std::SingleDispatch<Bfs, void, const graph::GraphBase &, const Node&, Bfs::Function>::RegistratorWrapper<void, graph::UndirectedGraph>(Bfs::bfs);
 
 void Bfs::bfs(const UndirectedGraph &graph, const Node &start, Bfs::FunctionExt func) {
 	bfs2_impl(graph, start, func);
 }
 
-auto BfsUndirectedGraph2 = Bfs::SingleDispatch<Bfs, void, const graph::GraphBase &, const Node&, Bfs::FunctionExt>::RegistratorWrapper<void, graph::UndirectedGraph>(Bfs::bfs);
+auto BfsUndirectedGraph2 = std::SingleDispatch<Bfs, void, const graph::GraphBase &, const Node&, Bfs::FunctionExt>::RegistratorWrapper<void, graph::UndirectedGraph>(Bfs::bfs);
 
 } // namespace traverse
 
diff --git a/alib2algo/src/graph/traverse/Dfs.cpp b/alib2algo/src/graph/traverse/Dfs.cpp
index 0eaa729f9e..50dcfea7a7 100644
--- a/alib2algo/src/graph/traverse/Dfs.cpp
+++ b/alib2algo/src/graph/traverse/Dfs.cpp
@@ -66,7 +66,7 @@ void Dfs::dfs(const DirectedGraph &graph, const Node &start, Dfs::Function func)
 	dfs_impl(graph, start, func);
 }
 
-auto DfsDirectedGraph1 = Dfs::SingleDispatch<Dfs, void, const graph::GraphBase &, const Node&, Dfs::Function>::RegistratorWrapper<void, graph::DirectedGraph>(Dfs::dfs);
+auto DfsDirectedGraph1 = std::SingleDispatch<Dfs, void, const graph::GraphBase &, const Node&, Dfs::Function>::RegistratorWrapper<void, graph::DirectedGraph>(Dfs::dfs);
 
 void Dfs::dfs(const DirectedGraph &graph, const Node &start, Dfs::FunctionExt func) {
 	int time = 0;
@@ -74,13 +74,13 @@ void Dfs::dfs(const DirectedGraph &graph, const Node &start, Dfs::FunctionExt fu
 	dfs2_impl(graph, start, start, visited, time, func);
 }
 
-auto DfsDirectedGraph2 = Dfs::SingleDispatch<Dfs, void, const graph::GraphBase &, const Node&, Dfs::FunctionExt>::RegistratorWrapper<void, graph::DirectedGraph>(Dfs::dfs);
+auto DfsDirectedGraph2 = std::SingleDispatch<Dfs, void, const graph::GraphBase &, const Node&, Dfs::FunctionExt>::RegistratorWrapper<void, graph::DirectedGraph>(Dfs::dfs);
 
 void Dfs::dfs(const UndirectedGraph &graph, const Node &start, Dfs::Function func) {
 	dfs_impl(graph, start, func);
 }
 
-auto DfsUndirectedGraph1 = Dfs::SingleDispatch<Dfs, void, const graph::GraphBase &, const Node&, Dfs::Function>::RegistratorWrapper<void, graph::UndirectedGraph>(Dfs::dfs);
+auto DfsUndirectedGraph1 = std::SingleDispatch<Dfs, void, const graph::GraphBase &, const Node&, Dfs::Function>::RegistratorWrapper<void, graph::UndirectedGraph>(Dfs::dfs);
 
 void Dfs::dfs(const UndirectedGraph &graph, const Node &start, Dfs::FunctionExt func) {
 	int time = 0;
@@ -88,7 +88,7 @@ void Dfs::dfs(const UndirectedGraph &graph, const Node &start, Dfs::FunctionExt
 	dfs2_impl(graph, start, start, visited, time, func);
 }
 
-auto DfsUndirectedGraph2 = Dfs::SingleDispatch<Dfs, void, const graph::GraphBase &, const Node&, Dfs::FunctionExt>::RegistratorWrapper<void, graph::UndirectedGraph>(Dfs::dfs);
+auto DfsUndirectedGraph2 = std::SingleDispatch<Dfs, void, const graph::GraphBase &, const Node&, Dfs::FunctionExt>::RegistratorWrapper<void, graph::UndirectedGraph>(Dfs::dfs);
 
 } // namespace traverse
 
diff --git a/alib2common/src/core/multipleDispatch.hpp b/alib2common/src/core/multipleDispatch.hpp
index 26e1ee366f..789d7d63d4 100644
--- a/alib2common/src/core/multipleDispatch.hpp
+++ b/alib2common/src/core/multipleDispatch.hpp
@@ -13,125 +13,86 @@
 #include <map>
 #include <iostream>
 #include <type_traits>
+#include <sstream>
 
 #include "../cast/CastApi.hpp"
 #include "../exception/CommonException.h"
 
 namespace std {
 
-template < class Algorithm, class ReturnType, class FirstParameterType, class ... StaticParamTypes >
-class SingleDispatch {
+template < class Algorithm, class ReturnType, class ... Params >
+class MultipleDispatch;
+
+template < class Algorithm, class ReturnType, class ... FrontStaticParamTypes, class ... DispatchedParameterTypes, class ... BackStaticParamTypes >
+class MultipleDispatch < Algorithm, ReturnType, tuple < FrontStaticParamTypes ... >, tuple < DispatchedParameterTypes ... >, tuple < BackStaticParamTypes ... > > {
 public:
 	class RegistratorWrapperBase {
 	public:
-		virtual ReturnType eval ( FirstParameterType &&, StaticParamTypes ... ) = 0;
+		virtual ReturnType eval ( FrontStaticParamTypes ..., DispatchedParameterTypes && ..., BackStaticParamTypes ... ) = 0;
 	};
 
 private:
-	std::map < std::type_index, RegistratorWrapperBase * > registeredFunctions;
+	map < typename TupleBuilder < type_index, sizeof ... ( DispatchedParameterTypes ) >::type, RegistratorWrapperBase * > registeredFunctions;
 
-	static SingleDispatch < Algorithm, ReturnType, FirstParameterType, StaticParamTypes ... > & getInstance ( ) {
-		static SingleDispatch < Algorithm, ReturnType, FirstParameterType, StaticParamTypes ... > res;
+	static MultipleDispatch < Algorithm, ReturnType, tuple < FrontStaticParamTypes ... >, tuple < DispatchedParameterTypes ... >, tuple < BackStaticParamTypes ... > > & getInstance ( ) {
+		static MultipleDispatch < Algorithm, ReturnType, tuple < FrontStaticParamTypes ... >, tuple < DispatchedParameterTypes ... >, tuple < BackStaticParamTypes ... > > res;
 
 		return res;
 	}
 
 public:
-	template < class RealReturnType, class RealFirstParameterTypeBase >
+	template < class RealReturnType, class ... RealParameterTypeBases >
 	class RegistratorWrapper : public RegistratorWrapperBase {
-		typedef typename match_cv_ref < FirstParameterType, RealFirstParameterTypeBase >::type RealFirstParameterType;
-
-		std::function < RealReturnType ( RealFirstParameterType &&, StaticParamTypes ... ) > callback;
+		function < RealReturnType ( FrontStaticParamTypes ..., typename match_cv_ref < DispatchedParameterTypes, RealParameterTypeBases >::type && ..., BackStaticParamTypes ... ) > callback;
 
 	public:
-		ReturnType eval ( FirstParameterType && first, StaticParamTypes ... res ) {
-			return ReturnType ( callback ( forward < RealFirstParameterType > ( static_cast < RealFirstParameterType && > ( first ) ), res ... ) );
+		ReturnType eval ( FrontStaticParamTypes ... front, DispatchedParameterTypes && ... dispatched, BackStaticParamTypes ... back ) {
+			return ReturnType ( callback ( front ..., forward < typename match_cv_ref < DispatchedParameterTypes, RealParameterTypeBases >::type > ( static_cast < typename match_cv_ref < DispatchedParameterTypes, RealParameterTypeBases >::type && > ( dispatched ) ) ..., back ... ) );
 		}
 
-		RegistratorWrapper ( RealReturnType ( * callback ) ( RealFirstParameterType &&, StaticParamTypes ... ) ) : callback ( callback ) {
-			if ( !getInstance ( ).registeredFunctions.insert ( std::make_pair ( std::type_index ( typeid ( RealFirstParameterType ) ), this ) ).second ) {
-				std::string firstType = std::cstringToString ( std::type_name < RealFirstParameterType > ( ) );
+		RegistratorWrapper ( RealReturnType ( * callback ) ( FrontStaticParamTypes ..., typename match_cv_ref < DispatchedParameterTypes, RealParameterTypeBases >::type && ..., BackStaticParamTypes ... ) ) : callback ( callback ) {
+			if ( !getInstance ( ).registeredFunctions.insert ( make_pair ( make_tuple ( type_index ( typeid ( typename match_cv_ref < DispatchedParameterTypes, RealParameterTypeBases >::type ) ) ... ), this ) ).second ) {
+				stringstream ss;
+				( void ) initializer_list < int > { ( ss << cstringToString ( type_name < typename match_cv_ref < DispatchedParameterTypes, RealParameterTypeBases >::type > ( ) ), 0 ) ... };
 
-				std::string classType = std::cstringToString ( std::type_name < Algorithm > ( ) );
+				string classType = cstringToString ( type_name < Algorithm > ( ) );
 
-				throw::exception::CommonException ( "Callback for " + firstType + " already registered on " + classType + "." );
+				throw::exception::CommonException ( "Callback for " + ss.str ( ) + " already registered on " + classType + "." );
 			}
 		}
 
 	};
 
-	static ReturnType dispatch ( FirstParameterType && first, StaticParamTypes ... res ) {
-		typename std::map < std::type_index, RegistratorWrapperBase * >::iterator callback = getInstance ( ).registeredFunctions.find ( std::type_index ( typeid ( first ) ) );
+	static ReturnType dispatch ( FrontStaticParamTypes ... front, DispatchedParameterTypes && ... dispatched, BackStaticParamTypes ... back ) {
+		typename map < typename TupleBuilder < type_index, sizeof ... ( DispatchedParameterTypes ) >::type, RegistratorWrapperBase * >::iterator callback = getInstance ( ).registeredFunctions.find ( make_tuple ( type_index ( typeid ( dispatched ) ) ... ) );
 
 		if ( callback == getInstance ( ).registeredFunctions.end ( ) ) {
-			std::string firstType = std::cstringToString ( std::type_name ( typeid ( first ) ) );
+			stringstream ss;
+			( void ) initializer_list < int > { ( ss << cstringToString ( type_name ( typeid ( dispatched ) ) ), 0 ) ... };
 
-			std::string classType = std::cstringToString ( std::type_name < Algorithm > ( ) );
+			string classType = cstringToString ( type_name < Algorithm > ( ) );
 
-			throw::exception::CommonException ( "Callback for " + firstType + " not registered on " + classType + "." );
+			throw::exception::CommonException ( "Callback for " + ss.str ( ) + " not registered on " + classType + "." );
 		}
 
-		return callback->second->eval ( forward < FirstParameterType > ( first ), res ... );
+		return callback->second->eval ( front ..., forward < DispatchedParameterTypes > ( dispatched ) ..., back ... );
 	}
 
 };
 
-template < class Algorithm, class ReturnType, class StaticParamType, class FirstParameterType >
-class SingleDispatchFirstStaticParam {
-public:
-	class RegistratorWrapperBase {
-	public:
-		virtual ReturnType eval ( StaticParamType, FirstParameterType && ) = 0;
-	};
-
-private:
-	std::map < std::type_index, RegistratorWrapperBase * > registeredFunctions;
-
-	static SingleDispatchFirstStaticParam < Algorithm, ReturnType, StaticParamType, FirstParameterType > & getInstance ( ) {
-		static SingleDispatchFirstStaticParam < Algorithm, ReturnType, StaticParamType, FirstParameterType > res;
-
-		return res;
-	}
-
-public:
-	template < class RealReturnType, class RealFirstParameterTypeBase >
-	class RegistratorWrapper : public RegistratorWrapperBase {
-		typedef typename match_cv_ref < FirstParameterType, RealFirstParameterTypeBase >::type RealFirstParameterType;
-
-		std::function < RealReturnType ( StaticParamType, RealFirstParameterType && ) > callback;
-
-	public:
-		ReturnType eval ( StaticParamType res, FirstParameterType && first ) {
-			return ReturnType ( callback ( res, forward < RealFirstParameterType > ( static_cast < RealFirstParameterType && > ( first ) ) ) );
-		}
-
-		RegistratorWrapper ( RealReturnType ( * callback ) ( StaticParamType, RealFirstParameterType && ) ) : callback ( callback ) {
-			if ( !getInstance ( ).registeredFunctions.insert ( std::make_pair ( std::type_index ( typeid ( RealFirstParameterType ) ), this ) ).second ) {
-				std::string firstType = std::cstringToString ( std::type_name < RealFirstParameterType > ( ) );
-
-				std::string classType = std::cstringToString ( std::type_name < Algorithm > ( ) );
-
-				throw::exception::CommonException ( "Callback for " + firstType + " already registered on " + classType + "." );
-			}
-		}
-
-	};
-
-	static ReturnType dispatch ( StaticParamType res, FirstParameterType && first ) {
-		typename std::map < std::type_index, RegistratorWrapperBase * >::iterator callback = getInstance ( ).registeredFunctions.find ( std::type_index ( typeid ( first ) ) );
-
-		if ( callback == getInstance ( ).registeredFunctions.end ( ) ) {
-			std::string firstType = std::cstringToString ( std::type_name ( typeid ( first ) ) );
+// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 
-			std::string classType = std::cstringToString ( std::type_name < Algorithm > ( ) );
+template < class Algorithm, class ReturnType, class FirstParameterType, class ... StaticParamTypes >
+using SingleDispatch = MultipleDispatch < Algorithm, ReturnType, tuple < >, tuple < FirstParameterType >, tuple < StaticParamTypes ... > >;
 
-			throw::exception::CommonException ( "Callback for " + firstType + " not registered on " + classType + "." );
-		}
+template < class Algorithm, class ReturnType, class StaticParamType, class FirstParameterType >
+using SingleDispatchFirstStaticParam = MultipleDispatch < Algorithm, ReturnType, tuple < StaticParamType >, tuple < FirstParameterType >, tuple < > >;
 
-		return callback->second->eval ( res, forward < FirstParameterType > ( first ) );
-	}
+template < class Algorithm, class ReturnType, class FirstParameterType, class SecondParameterType, class ... StaticParamTypes >
+using DoubleDispatch = MultipleDispatch < Algorithm, ReturnType, tuple < >, tuple < FirstParameterType, SecondParameterType >, tuple < StaticParamTypes ... > >;
 
-};
+template < class Algorithm, class ReturnType, class StaticParamType, class FirstParameterType, class SecondParameterType >
+using DoubleDispatchFirstStaticParam = MultipleDispatch < Algorithm, ReturnType, tuple < StaticParamType >, tuple < FirstParameterType, SecondParameterType >, tuple < > >;
 
 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 
@@ -217,132 +178,6 @@ public:
 
 };
 
-// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-
-template < class Algorithm, class ReturnType, class FirstParameterType, class SecondParameterType, class ... StaticParamType >
-class DoubleDispatch {
-public:
-	class RegistratorWrapperBase {
-	public:
-		virtual ReturnType eval ( FirstParameterType &&, SecondParameterType &&, StaticParamType ... ) = 0;
-	};
-
-private:
-	std::map < std::pair < std::type_index, std::type_index >, RegistratorWrapperBase * > registeredFunctions;
-
-	static DoubleDispatch < Algorithm, ReturnType, FirstParameterType, SecondParameterType, StaticParamType ... > & getInstance ( ) {
-		static DoubleDispatch < Algorithm, ReturnType, FirstParameterType, SecondParameterType, StaticParamType ... > res;
-
-		return res;
-	}
-
-public:
-	template < class RealReturnType, class RealFirstParameterTypeBase, class RealSecondParameterTypeBase >
-	class RegistratorWrapper : public RegistratorWrapperBase {
-		typedef typename match_cv_ref < FirstParameterType, RealFirstParameterTypeBase >::type RealFirstParameterType;
-		typedef typename match_cv_ref < SecondParameterType, RealSecondParameterTypeBase >::type RealSecondParameterType;
-
-		std::function < RealReturnType ( const RealFirstParameterType &, const RealSecondParameterType &, StaticParamType ... ) > callback;
-
-	public:
-		ReturnType eval ( FirstParameterType && first, SecondParameterType && second, StaticParamType ... res ) {
-			return ReturnType ( callback ( forward < RealFirstParameterType > ( ( RealFirstParameterType && ) first ), forward < RealSecondParameterType > ( ( RealSecondParameterType && ) second ), res ... ) );
-		}
-
-		RegistratorWrapper ( RealReturnType ( * callback ) ( const RealFirstParameterType &, const RealSecondParameterType &, StaticParamType ... ) ) : callback ( callback ) {
-			if ( !getInstance ( ).registeredFunctions.insert ( std::make_pair ( std::make_pair ( std::type_index ( typeid ( RealFirstParameterType ) ), std::type_index ( typeid ( RealSecondParameterType ) ) ), this ) ).second ) {
-				std::string firstType = std::cstringToString ( std::type_name < RealFirstParameterType > ( ) );
-
-				std::string secondType = std::cstringToString ( std::type_name < RealSecondParameterType > ( ) );
-
-				std::string classType = std::cstringToString ( std::type_name < Algorithm > ( ) );
-
-				throw::exception::CommonException ( "Callback for (" + firstType + ", " + secondType + ") already registered on " + classType + "." );
-			}
-		}
-
-	};
-
-	static ReturnType dispatch ( FirstParameterType && first, SecondParameterType && second, StaticParamType ... res ) {
-		typename std::map < std::pair < std::type_index, std::type_index >, RegistratorWrapperBase * >::iterator callback = getInstance ( ).registeredFunctions.find ( std::make_pair ( std::type_index ( typeid ( first ) ), std::type_index ( typeid ( second ) ) ) );
-
-		if ( callback == getInstance ( ).registeredFunctions.end ( ) ) {
-			std::string firstType = std::cstringToString ( std::type_name ( typeid ( first ) ) );
-
-			std::string secondType = std::cstringToString ( std::type_name ( typeid ( second ) ) );
-
-			std::string classType = std::cstringToString ( std::type_name < Algorithm > ( ) );
-
-			throw::exception::CommonException ( "Callback for (" + firstType + ", " + secondType + ") not registered on " + classType + "." );
-		}
-
-		return callback->second->eval ( forward < FirstParameterType > ( first ), forward < SecondParameterType > ( second ), res ... );
-	}
-
-};
-
-template < class Algorithm, class ReturnType, class StaticParamType, class FirstParameterType, class SecondParameterType >
-class DoubleDispatchFirstStaticParam {
-public:
-	class RegistratorWrapperBase {
-	public:
-		virtual ReturnType eval ( StaticParamType, FirstParameterType &&, SecondParameterType && ) = 0;
-	};
-
-private:
-	std::map < std::pair < std::type_index, std::type_index >, RegistratorWrapperBase * > registeredFunctions;
-
-	static DoubleDispatchFirstStaticParam < Algorithm, ReturnType, StaticParamType, FirstParameterType, SecondParameterType > & getInstance ( ) {
-		static DoubleDispatchFirstStaticParam < Algorithm, ReturnType, StaticParamType, FirstParameterType, SecondParameterType > res;
-
-		return res;
-	}
-
-public:
-	template < class RealReturnType, class RealFirstParameterTypeBase, class RealSecondParameterTypeBase >
-	class RegistratorWrapper : public RegistratorWrapperBase {
-		typedef typename match_cv_ref < FirstParameterType, RealFirstParameterTypeBase >::type RealFirstParameterType;
-		typedef typename match_cv_ref < SecondParameterType, RealSecondParameterTypeBase >::type RealSecondParameterType;
-
-		std::function < RealReturnType ( StaticParamType, RealFirstParameterType &&, RealSecondParameterType && ) > callback;
-
-	public:
-		ReturnType eval ( StaticParamType res, FirstParameterType && first, SecondParameterType && second ) {
-			return ReturnType ( callback ( res, forward < RealFirstParameterType > ( static_cast < RealFirstParameterType && > ( first ) ), forward < SecondParameterType > ( static_cast < SecondParameterType && > ( second ) ) ) );
-		}
-
-		RegistratorWrapper ( RealReturnType ( * callback ) ( StaticParamType, RealFirstParameterType &&, RealSecondParameterType && ) ) : callback ( callback ) {
-			if ( !getInstance ( ).registeredFunctions.insert ( std::make_pair ( std::make_pair ( std::type_index ( typeid ( RealFirstParameterType ) ), std::type_index ( typeid ( RealSecondParameterType ) ) ), this ) ).second ) {
-				std::string firstType = std::cstringToString ( std::type_name < RealFirstParameterType > ( ) );
-
-				std::string secondType = std::cstringToString ( std::type_name < RealSecondParameterType > ( ) );
-
-				std::string classType = std::cstringToString ( std::type_name < Algorithm > ( ) );
-
-				throw::exception::CommonException ( "Callback for (" + firstType + ", " + secondType + ") already registered on " + classType + "." );
-			}
-		}
-
-	};
-
-	static ReturnType dispatch ( StaticParamType res, FirstParameterType && first, SecondParameterType && second ) {
-		typename std::map < std::pair < std::type_index, std::type_index >, RegistratorWrapperBase * >::iterator callback = getInstance ( ).registeredFunctions.find ( std::make_pair ( std::type_index ( typeid ( first ) ), std::type_index ( typeid ( second ) ) ) );
-
-		if ( callback == getInstance ( ).registeredFunctions.end ( ) ) {
-			std::string firstType = std::cstringToString ( std::type_name ( typeid ( first ) ) );
-
-			std::string secondType = std::cstringToString ( std::type_name ( typeid ( second ) ) );
-
-			std::string classType = std::cstringToString ( std::type_name < Algorithm > ( ) );
-
-			throw::exception::CommonException ( "Callback for (" + firstType + ", " + secondType + ") not registered on " + classType + "." );
-		}
-
-		return callback->second->eval ( res, forward < FirstParameterType > ( first ), forward < SecondParameterType > ( second ) );
-	}
-
-};
-
 } /* namespace std */
 
 #endif /* MULTIPLE_DISPATCH_H_ */
diff --git a/alib2common/test-src/core/DispatchTest.cpp b/alib2common/test-src/core/DispatchTest.cpp
index 1c07302c13..9db314aec7 100644
--- a/alib2common/test-src/core/DispatchTest.cpp
+++ b/alib2common/test-src/core/DispatchTest.cpp
@@ -178,7 +178,7 @@ public:
 
 // -------------------------------------------------------------------------------------------------------------------------------------------------------
 
-class TmpVisitor : public std::SingleDispatch < TmpVisitor, int, const TmpBase & > {
+class TmpVisitor : public std::MultipleDispatch < TmpVisitor, int, std::tuple < >, std::tuple < const TmpBase & >, std::tuple < > > {
 public:
 	static int eval ( const Tmp2 & first ) {
 		std::cout << first << std::endl;
-- 
GitLab