[libsigc++2] C++11: Avoid the need for SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
- From: Kjell Ahlstedt <kjellahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsigc++2] C++11: Avoid the need for SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
- Date: Tue, 14 Jul 2015 14:37:20 +0000 (UTC)
commit bea45c135e403c0f609813e7425284d6e907f7e8
Author: Kjell Ahlstedt <kjell ahlstedt bredband net>
Date: Tue Jul 14 16:31:19 2015 +0200
C++11: Avoid the need for SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
* sigc++/adaptors/lambda/macros/base.h.m4:
* sigc++/adaptors/lambda/macros/group.h.m4:
* sigc++/adaptors/macros/track_obj.h.m4:
* sigc++/macros/signal.h.m4: Remove all talk about
SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE.
* sigc++/functors/slot_base.h: Mentioned that
SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE is not needed any more.
* tests/test_cpp11_lambda.cc:
* tests/test_track_obj.cc: Remove calls to
SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE and tests for C++11 capability.
* sigc++/functors/macros/functor_trait.h.m4: Add class
can_deduce_result_type_with_decltype<>. Use it as default value for the new
template parameter I_can_use_decltype in struct functor_trait<>.
Bug #672555.
Murray Cumming made the changes of all files except functor_trait.h.m4.
sigc++/adaptors/lambda/macros/base.h.m4 | 3 +-
sigc++/adaptors/lambda/macros/group.h.m4 | 3 +-
sigc++/adaptors/macros/track_obj.h.m4 | 1 -
sigc++/functors/macros/functor_trait.h.m4 | 108 +++++++++++++++++++---------
sigc++/functors/slot_base.h | 3 +-
sigc++/macros/signal.h.m4 | 2 +-
tests/test_cpp11_lambda.cc | 20 +-----
tests/test_track_obj.cc | 18 +----
8 files changed, 83 insertions(+), 75 deletions(-)
---
diff --git a/sigc++/adaptors/lambda/macros/base.h.m4 b/sigc++/adaptors/lambda/macros/base.h.m4
index efc9476..2ff91f4 100644
--- a/sigc++/adaptors/lambda/macros/base.h.m4
+++ b/sigc++/adaptors/lambda/macros/base.h.m4
@@ -344,8 +344,7 @@ dnl { return lambda<typename internal::convert_array<const T_type>::type>(v); }
* }
* @endcode
*
- * If your compiler supports C++11 lambda expressions, and you use the macro
- * #SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE, you can replace
+ * If you prefer to use C++11 lambda expressions, you can replace
* @code
* readValue.connect(sigc::var(data));
* @endcode
diff --git a/sigc++/adaptors/lambda/macros/group.h.m4 b/sigc++/adaptors/lambda/macros/group.h.m4
index c76d072..db962bf 100644
--- a/sigc++/adaptors/lambda/macros/group.h.m4
+++ b/sigc++/adaptors/lambda/macros/group.h.m4
@@ -163,8 +163,7 @@ _DEPRECATE_IFDEF_START
* @endcode
*
* The functor sigc::group() returns can be passed into sigc::signal::connect() directly.
- * A C++11 lambda expression can be passed into sigc::signal::connect() directly,
- * if either it returns <tt>void</tt>, or you use #SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE.
+ * A C++11 lambda expression can be passed into sigc::signal::connect() directly.
*
* @par Example:
* @code
diff --git a/sigc++/adaptors/macros/track_obj.h.m4 b/sigc++/adaptors/macros/track_obj.h.m4
index 78583b1..9f7d8c2 100644
--- a/sigc++/adaptors/macros/track_obj.h.m4
+++ b/sigc++/adaptors/macros/track_obj.h.m4
@@ -150,7 +150,6 @@ namespace sigc {
*
* @par Example:
* @code
- * namespace sigc { SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE }
* struct bar : public sigc::trackable {};
* sigc::signal<void> some_signal;
* void foo(bar&);
diff --git a/sigc++/functors/macros/functor_trait.h.m4 b/sigc++/functors/macros/functor_trait.h.m4
index 813d8d9..c5fc039 100644
--- a/sigc++/functors/macros/functor_trait.h.m4
+++ b/sigc++/functors/macros/functor_trait.h.m4
@@ -20,7 +20,7 @@ include(template.macros.m4)
define([FUNCTOR_PTR_FUN],[dnl
template <LIST(LOOP(class T_arg%1, $1), class T_return)> class pointer_functor$1;
template <LIST(LOOP(class T_arg%1, $1), class T_return)>
-struct functor_trait<T_return (*)(LOOP(T_arg%1, $1)), false>
+struct functor_trait<T_return (*)(LOOP(T_arg%1, $1)), false, false>
{
typedef T_return result_type;
typedef pointer_functor$1<LIST(LOOP(T_arg%1, $1), T_return)> functor_type;
@@ -31,13 +31,13 @@ define([FUNCTOR_MEM_FUN],[dnl
template <LIST(LOOP(class T_arg%1, $1), class T_return, class T_obj)> class mem_functor$1;
template <LIST(LOOP(class T_arg%1, $1), class T_return, class T_obj)> class const_mem_functor$1;
template <LIST(LOOP(class T_arg%1, $1), class T_return, class T_obj)>
-struct functor_trait<T_return (T_obj::*)(LOOP(T_arg%1, $1)), false>
+struct functor_trait<T_return (T_obj::*)(LOOP(T_arg%1, $1)), false, false>
{
typedef T_return result_type;
typedef mem_functor$1<LIST(LOOP(T_arg%1, $1), T_return, T_obj)> functor_type;
};
template <LIST(LOOP(class T_arg%1, $1), class T_return, class T_obj)>
-struct functor_trait<T_return (T_obj::*)(LOOP(T_arg%1, $1)) const, false>
+struct functor_trait<T_return (T_obj::*)(LOOP(T_arg%1, $1)) const, false, false>
{
typedef T_return result_type;
typedef const_mem_functor$1<LIST(LOOP(T_arg%1, $1), T_return, T_obj)> functor_type;
@@ -90,24 +90,19 @@ struct nil {};
* <tt>typedef T_return result_type;</tt> in the class definition.
* - Use the macro SIGC_FUNCTOR_TRAIT(T_functor,T_return) in namespace sigc.
* Multi-type functors are only partly supported.
+ * - For functors not derived from sigc::functor_base, and not specified with
+ * SIGC_FUNCTOR_TRAIT(), libsigc++ tries to deduce the result type with the
+ * C++11 decltype() specifier. That attempt usually succeeds if the functor
+ * has a single operator()(), but it fails if operator()() is overloaded.
* - Use the macro #SIGC_FUNCTORS_HAVE_RESULT_TYPE, if you want libsigc++ to assume
* that result_type is defined in all user-defined or third party functors,
- * except those for which you specify a return type explicitly with SIGC_FUNCTOR_TRAIT().
- * - Use the macro #SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE, if your
- * compiler makes it possible. Functors with overloaded operator()() are not
- * supported.
+ * whose result type can't be deduced in any other way.
*
- * The last alterative makes it possible to construct a slot from a C++11 lambda
- * expression with any return type. Example:
- * @code
- * namespace sigc {
- * SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
- * }
- * sigc::slot<bool, int> slot1 = [[]](int n)-> bool
- * {
- * return n == 42;
- * };
- * @endcode
+ * If all these ways to deduce the result type fail, void is assumed.
+ *
+ * With libsigc++ versions before 2.6, the macro
+ * #SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE activated the test with
+ * decltype(). That macro is now unneccesary and deprecated.
*/
/** A hint to the compiler.
@@ -117,16 +112,53 @@ struct nil {};
*/
struct functor_base {};
+/** Helper macro, to determine if decltype() can deduce the result type of a functor.
+ *
+ * @ingroup sigcfunctors
+ */
+template <typename T_functor>
+class can_deduce_result_type_with_decltype
+{
+private:
+ struct biggerthanint
+ {
+ int memory1;
+ int memory2;
+ int memory3;
+ int memory4;
+ };
+
+ static biggerthanint check(...);
+
+ // If decltype(&X_functor::operator()) can't be evaluated, this check() overload
+ // is ignored because of the SFINAE rule (Substitution Failure Is Not An Error).
+ template <typename X_functor>
+ static int check(X_functor* obj, decltype(&X_functor::operator()) p = nullptr);
+
+public:
+ static const bool value
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ = sizeof(check(static_cast<T_functor*>(nullptr))) == sizeof(int)
+#endif
+ ;
+};
+
+
/** Trait that specifies the return type of any type.
* Template specializations for functors derived from sigc::functor_base,
+ * for other functors whose result type can be deduced with decltype(),
* for function pointers and for class methods are provided.
*
* @tparam T_functor Functor type.
* @tparam I_derives_functor_base Whether @p T_functor inherits from sigc::functor_base.
+ * @tparam I_can_use_decltype Whether the result type of @p T_functor can be deduced
+ * with decltype().
*
* @ingroup sigcfunctors
*/
-template <class T_functor, bool I_derives_functor_base=is_base_and_derived<functor_base,T_functor>::value>
+template <class T_functor,
+ bool I_derives_functor_base = is_base_and_derived<functor_base,T_functor>::value,
+ bool I_can_use_decltype = can_deduce_result_type_with_decltype<T_functor>::value>
struct functor_trait
{
typedef void result_type;
@@ -134,12 +166,19 @@ struct functor_trait
};
#ifndef DOXYGEN_SHOULD_SKIP_THIS
-template <class T_functor>
-struct functor_trait<T_functor,true>
+template <class T_functor, bool I_can_use_decltype>
+struct functor_trait<T_functor, true, I_can_use_decltype>
{
typedef typename T_functor::result_type result_type;
typedef T_functor functor_type;
};
+
+template <typename T_functor>
+struct functor_trait<T_functor, false, true>
+{
+ typedef typename functor_trait<decltype(&T_functor::operator()), false, false>::result_type result_type;
+ typedef T_functor functor_type;
+};
#endif // DOXYGEN_SHOULD_SKIP_THIS
/** Helper macro, if you want to mix user-defined and third party functors with libsigc++.
@@ -150,14 +189,11 @@ struct functor_trait<T_functor,true>
* namespace sigc { SIGC_FUNCTORS_HAVE_RESULT_TYPE }
* @endcode
*
- * You can't use both SIGC_FUNCTORS_HAVE_RESULT_TYPE and
- * SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE in the same compilation unit.
- *
* @ingroup sigcfunctors
*/
#define SIGC_FUNCTORS_HAVE_RESULT_TYPE \
template <class T_functor> \
-struct functor_trait<T_functor,false> \
+struct functor_trait<T_functor, false, false> \
{ \
typedef typename T_functor::result_type result_type; \
typedef T_functor functor_type; \
@@ -180,12 +216,19 @@ struct functor_trait<T_functor,false> \
*/
#define SIGC_FUNCTOR_TRAIT(T_functor,T_return) \
template <> \
-struct functor_trait<T_functor,false> \
+struct functor_trait<T_functor, false, false> \
+{ \
+ typedef T_return result_type; \
+ typedef T_functor functor_type; \
+}; \
+template <> \
+struct functor_trait<T_functor, false, true> \
{ \
typedef T_return result_type; \
typedef T_functor functor_type; \
};
+#ifndef SIGCXX_DISABLE_DEPRECATED
/** Helper macro, if you want to mix user-defined and third party functors with libsigc++.
*
* If you want to mix functors not derived from sigc::functor_base with libsigc++,
@@ -201,18 +244,13 @@ struct functor_trait<T_functor,false> \
*
* @newin{2,2,11}
*
- * You can't use both SIGC_FUNCTORS_HAVE_RESULT_TYPE and
- * SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE in the same compilation unit.
+ * @deprecated This macro does nothing. The test it activated in libsigc++
+ * versions before 2.6, is now unconditionally activated.
*
* @ingroup sigcfunctors
*/
-#define SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE \
-template <typename T_functor> \
-struct functor_trait<T_functor, false> \
-{ \
- typedef typename functor_trait<decltype(&T_functor::operator()), false>::result_type result_type; \
- typedef T_functor functor_type; \
-};
+#define SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE // Empty
+#endif // SIGCXX_DISABLE_DEPRECATED
#ifndef DOXYGEN_SHOULD_SKIP_THIS
// detect the return type and the functor version of non-functor types.
diff --git a/sigc++/functors/slot_base.h b/sigc++/functors/slot_base.h
index 69acef7..29c64c1 100644
--- a/sigc++/functors/slot_base.h
+++ b/sigc++/functors/slot_base.h
@@ -209,7 +209,8 @@ struct SIGC_API slot_do_unbind
*
* If you connect a C++11 lambda expression or a std::function<> instance to
* a signal or assign it to a slot,
- * - if the return type is not void, you must use the #SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE macro,
+ * - With libsigc++ versions before 2.6, if the return type is not void,
+ you must use the #SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE macro,
* - if your functor contains references to sigc::trackable derived objects,
* those objects will not be tracked, unless you also use sigc::track_obj().
*
diff --git a/sigc++/macros/signal.h.m4 b/sigc++/macros/signal.h.m4
index 03deae0..7a42c7e 100644
--- a/sigc++/macros/signal.h.m4
+++ b/sigc++/macros/signal.h.m4
@@ -331,7 +331,7 @@ public:
*
* %std::bind() creates a functor, but this functor typically has an
* %operator()() which is a variadic template.
- * #SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE can't deduce the result type
+ * Our functor_trait can't deduce the result type
* of such a functor. If you first assign the return value of %std::bind()
* to a std::function, you can connect the std::function to a signal.
*
diff --git a/tests/test_cpp11_lambda.cc b/tests/test_cpp11_lambda.cc
index e9b2ba7..be732b9 100644
--- a/tests/test_cpp11_lambda.cc
+++ b/tests/test_cpp11_lambda.cc
@@ -42,9 +42,6 @@
// echo $?
// If test_cpp11_lambda writes nothing and the return code is 0, the test has passed.
-#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || _MSC_VER >= 1700
-# define USING_CPP11_LAMBDA_EXPRESSIONS
-#endif
#include "testutilities.h"
#include <string>
@@ -58,11 +55,6 @@
#include <sigc++/adaptors/track_obj.h>
#include <sigc++/signal.h>
-#ifdef USING_CPP11_LAMBDA_EXPRESSIONS
-namespace sigc
-{
- SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
-}
namespace
{
@@ -145,7 +137,6 @@ void foo_group4(bar_group4&)
} // end anonymous namespace
-#endif // USING_CPP11_LAMBDA_EXPRESSIONS
int main(int argc, char* argv[])
@@ -155,7 +146,6 @@ int main(int argc, char* argv[])
if (!util->check_command_args(argc, argv))
return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
-#ifdef USING_CPP11_LAMBDA_EXPRESSIONS
// test lambda operators
int a = 1;
@@ -322,8 +312,7 @@ int main(int argc, char* argv[])
// std::bind() does not work well together with sigc::slot and sigc::signal::connect().
// std::bind() typically creates a functor whose operator()() is a variadic template.
- // SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE can't deduce the result type
- // of such a functor.
+ // Our functor_trait can't deduce the result type of such a functor.
// If the result of std::bind() is assigned to a std::function, the created
// functor has an unambiguous operator()().
@@ -505,11 +494,6 @@ int main(int argc, char* argv[])
some_signal.emit();
util->check_result(result_stream, "");
}
- return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
-#else // not USING_CPP11_LAMBDA_EXPRESSIONS
- std::cout << "The compiler capabilities don't allow test of C++11 lambda expressions." << std::endl;
- // Return code 77 tells automake's test harness to skip this test.
- return util->get_result_and_delete_instance() ? 77 : EXIT_FAILURE;
-#endif
+ return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
} // end main()
diff --git a/tests/test_track_obj.cc b/tests/test_track_obj.cc
index 9807e95..e3345d3 100644
--- a/tests/test_track_obj.cc
+++ b/tests/test_track_obj.cc
@@ -33,9 +33,6 @@
// echo $?
// If test_track_obj writes nothing and the return code is 0, the test has passed.
-#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || _MSC_VER >= 1700
-# define USING_CPP11_LAMBDA_EXPRESSIONS
-#endif
#include "testutilities.h"
#include <string>
@@ -45,12 +42,6 @@
#include <sigc++/adaptors/track_obj.h>
#include <sigc++/signal.h>
-#ifdef USING_CPP11_LAMBDA_EXPRESSIONS
-namespace sigc
-{
- SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
-}
-#endif
namespace
{
@@ -106,7 +97,7 @@ private:
const book& aBook_;
};
-#ifdef USING_CPP11_LAMBDA_EXPRESSIONS
+//C++11 lamba expressions:
inline std::ostringstream& operator << (std::ostringstream& s, const book& b)
{
@@ -124,7 +115,6 @@ void foo_group4(bar_group4&)
{
result_stream << "foo_group4(bar_group4&)";
}
-#endif // USING_CPP11_LAMBDA_EXPRESSIONS
} // end anonymous namespace
@@ -166,7 +156,8 @@ int main(int argc, char* argv[])
delete pbar4;
pbar4 = 0;
-#ifdef USING_CPP11_LAMBDA_EXPRESSIONS
+
+//C++11 lambda expressions:
// auto-disconnect
// If you want to auto-disconnect a slot with a C++11 lambda expression
@@ -225,9 +216,6 @@ int main(int argc, char* argv[])
util->check_result(result_stream, "");
}
-#else // not USING_CPP11_LAMBDA_EXPRESSIONS
- std::cout << "The compiler capabilities don't allow test of C++11 lambda expressions." << std::endl;
-#endif
return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]