[libsigc++2] C++11: Avoid the need for SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE



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]