From 312dd57b1d79677eb8eced549c6e5039acfdfebe Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Sat, 15 Sep 2018 21:04:38 +0200
Subject: [PATCH] add trait to test whether callable accepts given params

---
 alib2std/src/extensions/type_traits.hpp       | 35 +++++++++++++++++++
 .../test-src/extensions/TypeTraitsTest.cpp    | 12 +++++++
 alib2std/test-src/extensions/TypeTraitsTest.h |  2 ++
 3 files changed, 49 insertions(+)

diff --git a/alib2std/src/extensions/type_traits.hpp b/alib2std/src/extensions/type_traits.hpp
index 7161c28094..12756c1aeb 100644
--- a/alib2std/src/extensions/type_traits.hpp
+++ b/alib2std/src/extensions/type_traits.hpp
@@ -53,6 +53,41 @@ namespace ext {
 		static const bool value = sizeof(Yes) == sizeof(has_clone::test((typename std::decay<T>::type*)0));
 	};
 
+	/**
+	 * \brief
+	 * Positive supports test implementation. The test is designed to detect call availability on callable F with parameters Ts ...
+	 *
+	 * \tparam F the type of callable
+	 * \tparam Ts ... call parameter types
+	 *
+	 * \returns std::true_type
+	 */
+	template < class F, class ... Ts, typename = decltype ( std::declval < F > ( ) ( std::declval < Ts > ( ) ... ) ) >
+	std::true_type supports_test ( const F &, const Ts & ... );
+
+	/**
+	 * \brief
+	 * Negative supports test implementation. The test is designed to be callback when the positive test failed.
+	 *
+	 * \returns std::false_type
+	 */
+	std::false_type supports_test ( ... );
+
+	/**
+	 * Base implementation of the call test support.
+	 */
+	template < class > struct supports;
+
+	/**
+	 * Specialisation of the call test support for F type be a callable.
+	 *
+	 * \tparam F the type of callable
+	 * \tparam Ts ... call parameter types
+	 *
+	 * If the call with parameter types Ts ... is possible on callable F, the class provides a value of type true, othervise a false value filed is provided.
+	 */
+	template < class F, class ... Ts > struct supports < F ( Ts ... ) > : decltype ( supports_test ( std::declval < F > ( ), std::declval < Ts > ( ) ... ) ) { };
+
 // ----------------------------------------------------------------------------------------------------
 
 	/**
diff --git a/alib2std/test-src/extensions/TypeTraitsTest.cpp b/alib2std/test-src/extensions/TypeTraitsTest.cpp
index 7917890025..d92457fcf0 100644
--- a/alib2std/test-src/extensions/TypeTraitsTest.cpp
+++ b/alib2std/test-src/extensions/TypeTraitsTest.cpp
@@ -30,3 +30,15 @@ void TypeTraitsTest::testTypeNames() {
 	CPPUNIT_ASSERT ( ext::to_string < Bar > ( ) == "Bar" );
 	CPPUNIT_ASSERT ( ext::to_string < int > ( ) == "int" );
 }
+
+bool operator < ( const Foo &, int ) {
+	return false;
+}
+
+void TypeTraitsTest::testSupports() {
+	CPPUNIT_ASSERT ( ext::supports < std::less < > ( int, int ) >::value == true );
+	CPPUNIT_ASSERT ( ext::supports < std::less < > ( unsigned, int ) >::value == true );
+	CPPUNIT_ASSERT ( ext::supports < std::less < > ( double, char ) >::value == true );
+	CPPUNIT_ASSERT ( ext::supports < std::less < > ( Foo, char ) >::value == true );
+	CPPUNIT_ASSERT ( ext::supports < std::less < > ( Foo, Foo ) >::value == false );
+}
diff --git a/alib2std/test-src/extensions/TypeTraitsTest.h b/alib2std/test-src/extensions/TypeTraitsTest.h
index 0c3ed628d8..3ef045b9ec 100644
--- a/alib2std/test-src/extensions/TypeTraitsTest.h
+++ b/alib2std/test-src/extensions/TypeTraitsTest.h
@@ -7,6 +7,7 @@ class TypeTraitsTest : public CppUnit::TestFixture {
 	CPPUNIT_TEST_SUITE( TypeTraitsTest );
 	CPPUNIT_TEST( testTypeInPack );
 	CPPUNIT_TEST( testTypeNames );
+	CPPUNIT_TEST( testSupports );
 	CPPUNIT_TEST_SUITE_END();
 
 public:
@@ -15,6 +16,7 @@ public:
 
 	void testTypeInPack();
 	void testTypeNames();
+	void testSupports();
 };
 
 #endif  // TYPE_TRAITS_TEST_H_
-- 
GitLab