[libsigc++2] Add SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH for C++11 lambda expressions.



commit 41cf46e0fca8128abab298f54209d427a5a6c1b9
Author: Kjell Ahlstedt <kjell ahlstedt bredband net>
Date:   Tue Aug 28 19:40:24 2012 +0200

    Add SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH for C++11 lambda expressions.
    
    * sigc++/functors/macros/functor_trait.h.m4: Add the preprocessor macro
    SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH(C_keyword), which makes it possible to
    assign C++11 lambda expressions with any return type to slots.
    Thanks to Chow Loong Jin, who posted similar code on libsigc-list.
    * sigc++/adaptors/lambda/macros/base.h.m4:
    * sigc++/adaptors/lambda/macros/group.h.m4: Add information on C++11 lambda
    expressions to the documentation of lambda expressions and sigc::group().
    * tests/Makefile.am: Add test_cpp11_lambda.cc.
    * tests/test_cpp11_lambda.cc: New test case, showing that most uses of
    libsigc++'s lambda expressions can be replaced by standard C++11 lambda
    expressions. Bug #672555.

 ChangeLog                                 |   16 +
 sigc++/adaptors/lambda/macros/base.h.m4   |   28 ++-
 sigc++/adaptors/lambda/macros/group.h.m4  |   34 ++-
 sigc++/functors/macros/functor_trait.h.m4 |  110 +++++--
 tests/Makefile.am                         |    2 +
 tests/test_cpp11_lambda.cc                |  483 +++++++++++++++++++++++++++++
 6 files changed, 635 insertions(+), 38 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index f8d6870..2077c7e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2012-08-28  Kjell Ahlstedt  <kjell ahlstedt bredband net>
+
+	Add SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH for C++11 lambda expressions.
+
+	* sigc++/functors/macros/functor_trait.h.m4: Add the preprocessor macro
+	SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH(C_keyword), which makes it possible to
+	assign C++11 lambda expressions with any return type to slots.
+	Thanks to Chow Loong Jin, who posted similar code on libsigc-list.
+	* sigc++/adaptors/lambda/macros/base.h.m4:
+	* sigc++/adaptors/lambda/macros/group.h.m4: Add information on C++11 lambda
+	expressions to the documentation of lambda expressions and sigc::group().
+	* tests/Makefile.am: Add test_cpp11_lambda.cc.
+	* tests/test_cpp11_lambda.cc: New test case, showing that most uses of
+	libsigc++'s lambda expressions can be replaced by standard C++11 lambda
+	expressions. Bug #672555.
+
 2012-03-19  Kjell Ahlstedt  <kjell ahlstedt bredband net>
 
 	Enable test_lambda in 'make check'.
diff --git a/sigc++/adaptors/lambda/macros/base.h.m4 b/sigc++/adaptors/lambda/macros/base.h.m4
index 7a558dd..649ba47 100644
--- a/sigc++/adaptors/lambda/macros/base.h.m4
+++ b/sigc++/adaptors/lambda/macros/base.h.m4
@@ -57,7 +57,8 @@ divert(0)dnl
 namespace sigc {
 
 /** @defgroup lambdas Lambdas
- * libsigc++ ships with basic lambda functionality and the sigc::group adaptor, which uses lambdas to transform a functor's parameter list.
+ * libsigc++ ships with basic lambda functionality and the sigc::group adaptor,
+ * which uses lambdas to transform a functor's parameter list.
  *
  * The lambda selectors sigc::_1, sigc::_2, ..., sigc::_9 are used to select the
  * first, second, ..., nineth argument from a list.
@@ -66,7 +67,6 @@ namespace sigc {
  * @code
  * std::cout << sigc::_1(10,20,30); // returns 10
  * std::cout << sigc::_2(10,20,30); // returns 20
- * ...
  * @endcode
  *
  * Operators are defined so that, for example, lambda selectors can be used as
@@ -77,6 +77,16 @@ namespace sigc {
  * std::cout << (sigc::_1 + 5)(3); // returns (3 + 5)
  * std::cout << (sigc::_1 * sigc::_2)(7,10); // returns (7 * 10)
  * @endcode
+ *
+ * If your compiler supports C++11 lambda expressions, they are often a good
+ * alternative to libsigc++'s lambda expressions. The following examples are
+ * equivalent to the previous ones.
+ * @code
+ * [[]] (int x, int, int) -> int { return x; }(10,20,30); // returns 10
+ * [[]] (int, int y, int) -> int { return y; }(10,20,30); // returns 20
+ * [[]] (int x) -> int { return x + 5; }(3); // returns (3 + 5)
+ * [[]] (int x, int y) -> int { return x * y; }(7,10); // returns (7 * 10)
+ * @endcode
  */
 
 /** A hint to the compiler.
@@ -268,10 +278,20 @@ dnl { return lambda<typename internal::convert_array<const T_type>::type>(v); }
  *   data = 3;
  *   std::cout << readValue() << std::endl; //Prints 3.
  *
- *  data = 5;
- *  std::cout << readValue() << std::endl; //Prints 5.
+ *   data = 5;
+ *   std::cout << readValue() << std::endl; //Prints 5.
  * }
  * @endcode
+ *
+ * If your compiler supports C++11 lambda expressions, and you use the macro
+ * SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH(), you can replace
+ * @code
+ * readValue.connect(sigc::var(data));
+ * @endcode
+ * in the example by
+ * @code
+ * readValue.connect([[&data]] () -> int { return data; });
+ * @endcode
  */
 template <class T_type>
 lambda<T_type&> var(T_type& v)
diff --git a/sigc++/adaptors/lambda/macros/group.h.m4 b/sigc++/adaptors/lambda/macros/group.h.m4
index 115d755..02b88ae 100644
--- a/sigc++/adaptors/lambda/macros/group.h.m4
+++ b/sigc++/adaptors/lambda/macros/group.h.m4
@@ -114,31 +114,43 @@ __FIREWALL__
  * arguments passed into the new functor. Arguments that don't have a placeholder in one
  * of the lambda expressions are dropped.
  *
+ * If you have a C++11 compiler, a C++11 lambda expression and/or std::bind() is
+ * often a good alternative to sigc::group(). Such alternatives are shown in the
+ * following examples, marked with the comment <tt>//C++11</tt>.
+ *
  * @par Examples:
  * @code
  * void foo(int, int);
  * int bar(int);
  * // argument binding ...
  * sigc::group(&foo,10,sigc::_1)(20); //fixes the first argument and calls foo(10,20)
+ * std::bind(&foo, 10, std::placeholders::_1)(20); //C++11
  * sigc::group(&foo,sigc::_1,30)(40); //fixes the second argument and calls foo(40,30)
+ * std::bind(&foo, std::placeholders::_1, 30)(40); //C++11
  * // argument reordering ...
  * sigc::group(&foo,sigc::_2,sigc::_1)(1,2); //calls foo(2,1)
+ * std::bind(&foo, std::placeholders::_2, std::placeholders::_1)(1,2); //C++11
  * // argument hiding ...
  * sigc::group(&foo,sigc::_1,sigc::_2)(1,2,3); //calls foo(1,2)
+ * std::bind(&foo, std::placeholders::_1, std::placeholders::_2)(1,2,3); //C++11
  * // functor composition ...
  * sigc::group(&foo,sigc::_1,sigc::group(&bar,sigc::_2))(1,2); //calls foo(1,bar(2))
+ * std::bind(&foo,  std::placeholders::_1, std::bind(&bar, std::placeholders::_2))(1,2); //C++11
  * // algebraic expressions ...
  * sigc::group(&foo,sigc::_1*sigc::_2,sigc::_1/sigc::_2)(6,3); //calls foo(6*3,6/3)
+ * [[&foo]] (int x, int y) { foo(x*y, x/y); }(6,3); //C++11
  * @endcode
  *
- * The functor sigc::group() returns can be passed into
- * sigc::signal::connect() directly.
+ * 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().
  *
  * @par Example:
  * @code
  * sigc::signal<void,int,int> some_signal;
  * void foo(int);
  * some_signal.connect(sigc::group(&foo,sigc::_2));
+ * some_signal.connect([[&foo]](int, int y) { foo(y); }); //C++11
  * @endcode
  *
  * Like in sigc::bind(), you can bind references to functors by passing the objects
@@ -150,6 +162,7 @@ __FIREWALL__
  * sigc::signal<void> some_signal;
  * void foo(int&);
  * some_signal.connect(sigc::group(&foo,sigc::ref(some_int)));
+ * some_signal.connect([[&foo, &some_int]](){ foo(some_int); }); //C++11
  * @endcode
  *
  * If you bind an object of a sigc::trackable derived type to a functor
@@ -165,7 +178,22 @@ __FIREWALL__
  *   // disconnected automatically if some_bar goes out of scope
  * @endcode
  *
- * @ingroup adaptors, lambdas
+ * std::bind() and C++11 lambda expressions fail here. If you store a
+ * reference to a sigc::trackable derived object in a C++11 lambda expression,
+ * and assign this expression to a slot or signal, it will not be disconnected
+ * automatically when the object goes out of scope. The previous example can
+ * still be rewritten without sigc::group().
+ * @code
+ * struct bar : public sigc::trackable {} some_bar;
+ * sigc::signal<void> some_signal;
+ * void foo(bar&);
+ * some_signal.connect(sigc::bind(&foo, sigc::ref(some_bar)));
+ *   // disconnected automatically if some_bar goes out of scope
+ * some_signal.connect([[&foo, &some_bar]](){ foo(some_bar); }); //C++11
+ *   // NOT disconnected automatically if some_bar goes out of scope
+ * @endcode
+ *
+ * @ingroup adaptors lambdas
  */
 
 namespace sigc {
diff --git a/sigc++/functors/macros/functor_trait.h.m4 b/sigc++/functors/macros/functor_trait.h.m4
index f5997da..fd15c69 100644
--- a/sigc++/functors/macros/functor_trait.h.m4
+++ b/sigc++/functors/macros/functor_trait.h.m4
@@ -46,31 +46,6 @@ struct functor_trait<T_return (T_obj::*)(LOOP(T_arg%1, $1)) const, false>
 ])
 
 divert(0)dnl
-/*
-  Trait functor_trait<functor>:
-
-  This trait allows the user to specific what is the return type
-  of any type. It has been overloaded to detect the return type and
-  the functor version of function pointers and class methods as well.
-
-  To populate the return type of user defined and third party functors
-  use the macro SIGC_FUNCTOR_TRAIT(T_functor,T_return) in
-  namespace sigc. Multi-type functors are only partly supported.
-  Try specifying the return type of the functor's operator()() overload.
-
-  Alternatively, you can derive your functors from functor_base and
-  place "typedef T_return result_type;" in the class definition.
-
-  Use SIGC_FUNCTORS_HAVE_RESULT_TYPE if you want sigc++ to assume that
-  result_type is defined in all user defined or 3rd-party functors
-  (except those you specify a return type explicitly with SIGC_FUNCTOR_TRAIT()).
-
-dnl 01.11.2003: Completely removed support for typeof() since it is non-standard!
-dnl   You might get away without these conventions if your compiler supports
-dnl   typeof() and if you don't happen to use the operator()() overload of
-dnl   sigc++'s adaptors in your program.
-dnl 
-*/
 __FIREWALL__
 #include <sigc++/type_traits.h>
 
@@ -98,12 +73,39 @@ struct nil;
  * Adaptors are functors that alter the signature of a functor's operator()().
  *
  * libsigc++ defines numerous functors, closures and adaptors.
- * Since libsigc++ is a callback libaray, most functors are also closures.
+ * Since libsigc++ is a callback library, most functors are also closures.
  * The documentation doesn't distinguish between functors and closures.
  *
  * The basic functor types libsigc++ provides are created with ptr_fun() and mem_fun()
  * and can be converted into slots implicitly.
  * The set of adaptors that ships with libsigc++ is documented in the @ref adaptors module.
+ *
+ * If you want to mix user-defined and third party functors with libsigc++,
+ * and you want them to be implicitly convertible into slots, libsigc++ must know
+ * the result type of your functors. There are different ways to achieve that.
+ *
+ * - Derive your functors from sigc::functor_base and place
+ *   <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.
+ * - Use the macro #SIGC_FUNCTORS_HAVE_RESULT_TYPE, if you want sigc++ 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(C_keyword), if your
+ *   compiler makes it possible. Functors with overloaded operator()() are not
+ *   supported.
+ *
+ * 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
  */
 
 /** A hint to the compiler.
@@ -113,7 +115,15 @@ struct nil;
  */
 struct functor_base {};
 
-
+/** Trait that specifies the return type of any type.
+ * Template specializations for functors derived from sigc::functor_base,
+ * 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.
+ *
+ * @ingroup sigcfunctors
+ */
 template <class T_functor, bool I_derives_functor_base=is_base_and_derived<functor_base,T_functor>::value>
 struct functor_trait
 {
@@ -128,12 +138,17 @@ struct functor_trait<T_functor,true>
   typedef T_functor functor_type;
 };
 
-/** If you want to mix functors from a different library with libsigc++ and
- * these functors define @p result_type simply use this macro inside namespace sigc like so:
+/** 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++, and
+ * these functors define @p result_type, use this macro inside namespace sigc like so:
  * @code
  * 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 in the same compilation unit.
+ *
  * @ingroup sigcfunctors
  */
 #define SIGC_FUNCTORS_HAVE_RESULT_TYPE                 \
@@ -144,8 +159,10 @@ struct functor_trait<T_functor,false>                  \
   typedef T_functor functor_type;                      \
 };
 
-/** If you want to mix functors from a different library with libsigc++ and
- * these functors don't define @p result_type use this macro inside namespace sigc
+/** 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++, and
+ * these functors don't define @p result_type, use this macro inside namespace sigc
  * to expose the return type of the functors like so:
  * @code
  * namespace sigc {
@@ -165,6 +182,37 @@ struct functor_trait<T_functor,false>          \
   typedef T_functor functor_type;              \
 };
 
+/** 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++, and
+ * your compiler can deduce the result type of the functor, use this macro inside
+ * namespace sigc like so:
+ * @code
+ * namespace sigc {
+ *   SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH(compiler_keyword)
+ * }
+ * @endcode
+ *
+ * For example, if your compiler understands the C++11 keyword <tt>decltype</tt>:
+ * @code
+ * namespace sigc {
+ *   SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH(decltype)
+ * }
+ * @endcode
+ *
+ * You can't use both SIGC_FUNCTORS_HAVE_RESULT_TYPE and
+ * SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH in the same compilation unit.
+ *
+ * @ingroup sigcfunctors
+ */
+#define SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH(C_keyword) \
+template <typename T_functor>          \
+struct functor_trait<T_functor, false> \
+{                                      \
+  typedef typename functor_trait<C_keyword(&T_functor::operator()), false>::result_type result_type; \
+  typedef T_functor functor_type;      \
+};
+
 // detect the return type and the functor version of non-functor types.
 FOR(0,CALL_SIZE,[[FUNCTOR_PTR_FUN(%1)]])
 FOR(0,CALL_SIZE,[[FUNCTOR_MEM_FUN(%1)]])
diff --git a/tests/Makefile.am b/tests/Makefile.am
index af20d84..6fd1dcb 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -26,6 +26,7 @@ check_PROGRAMS =			\
 	test_bind_ref			\
 	test_bind_refptr 		\
 	test_bind_return		\
+	test_cpp11_lambda		\
 	test_compose			\
 	test_copy_invalid_slot		\
 	test_custom			\
@@ -55,6 +56,7 @@ test_bind_SOURCES			= test_bind.cc
 test_bind_ref_SOURCES			= test_bind_ref.cc
 test_bind_refptr_SOURCES		= test_bind_refptr.cc
 test_bind_return_SOURCES		= test_bind_return.cc
+test_cpp11_lambda_SOURCES   = test_cpp11_lambda.cc
 test_compose_SOURCES			= test_compose.cc
 test_copy_invalid_slot_SOURCES		= test_copy_invalid_slot.cc
 test_custom_SOURCES			= test_custom.cc
diff --git a/tests/test_cpp11_lambda.cc b/tests/test_cpp11_lambda.cc
new file mode 100644
index 0000000..9e67b22
--- /dev/null
+++ b/tests/test_cpp11_lambda.cc
@@ -0,0 +1,483 @@
+/* Copyright (C) 2012 The libsigc++ Development Team
+ *
+ * This file is part of libsigc++.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// The purpose of this test case is threefold.
+// - Test that C++11 lambda expressions can be used in connection with sigc::slot
+//   and sigc::signal.
+// - Show that libsigc++ lambda expressions can be replaced by C++11 lambda
+//   expressions. It's shown here as a preparation for deprecating and eventually
+//   deleting the libsigc++ lambda expressions.
+//   See https://bugzilla.gnome.org/show_bug.cgi?id=672555
+// - Test the code examples in the documentation in sigc++/adaptors/lambda/base.h
+//   and sigc++/adaptors/lambda/group.h.
+//
+// At present (August 2012) this test case contains approximately the same tests
+// as test_lambda.cc, but with libsigc++ lambda expressions replaced by C++11
+// lambda expressions, where possible.
+// The only real disadvantage of the C++11 lambda expressions is that a slot that
+// contains an object derived from sigc::trackable is not automatically disconnected
+// when the object is deleted, if a reference to the object is stored in a C++11
+// lambda expression, connected to the slot.
+//
+// To test the C++11 lambda expressions with gcc 4.6.3 (and probably some later
+// versions of gcc):
+//   make CXXFLAGS='-g -O2 -std=c++0x' test_cpp11_lambda
+//   ./test_cpp11_lambda
+//   echo $?
+// If test_cpp11_lambda writes nothing and the return code is 0, the test has passed.
+
+#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
+#  define USING_CPP11_LAMBDA_EXPRESSIONS
+#endif
+
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <functional>
+#include <stdlib.h>
+#include <sigc++/functors/functors.h>
+#include <sigc++/bind.h>
+#include <sigc++/reference_wrapper.h>
+#include <sigc++/signal.h>
+
+#ifdef USING_CPP11_LAMBDA_EXPRESSIONS
+namespace sigc
+{
+  SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH(decltype)
+}
+#endif
+
+namespace
+{
+bool result_ok = true;
+int test_number = 0;
+std::ostringstream result_stream;
+
+void check_result(const std::string& expected_result)
+{
+  ++test_number;
+  if (expected_result != result_stream.str())
+  {
+    std::cout << "Test " << test_number << ". Expected \"" << expected_result
+      << "\", got \"" << result_stream.str() << "\"" << std::endl;
+    result_ok = false;
+  }
+  result_stream.str("");
+}
+
+int foo(int i, int j)
+{
+  result_stream << "foo(int " << i << ", int " << j << ")";
+  return 4*i + j;
+}
+
+void foo_void(int i)
+{
+  result_stream << "foo_void(int " << i << ")";
+}
+
+struct bar
+{
+  int test(int i, int j)
+  {
+    result_stream << "bar::test(int " << i << ", int " << j << ")";
+    return 4*i + j;
+  }
+
+  void test_void(int i)
+  {
+    result_stream << "bar::test_void(int " << i << ")";
+  }
+};
+
+void egon(std::string& str)
+{
+  result_stream << "egon(string '" << str << "')";
+  str = "egon was here";
+}
+
+struct book : public sigc::trackable
+{
+  explicit book(const std::string& name) : name_(name) {}
+  operator std::string& () { return name_; }
+  std::string name_;
+};
+
+inline std::ostringstream& operator << (std::ostringstream& s, const book& b)
+{
+  s << b.name_;
+  return s;
+}
+
+void foo_group1(int i, int j)
+{
+  result_stream << "foo_group1(int " << i << ", int " << j << ")";
+}
+
+int bar_group1(int i)
+{
+  result_stream << "bar_group1(int " << i << ")";
+  return i + 2;
+}
+
+void foo_group2(int i)
+{
+  result_stream << "foo_group2(int " << i << ")";
+}
+
+void foo_group3(int& i)
+{
+  result_stream << "foo_group3(int " << i << ")";
+  ++i;
+}
+
+struct bar_group4 : public sigc::trackable
+{
+};
+
+void foo_group4(bar_group4&)
+{
+  result_stream << "foo_group4(bar_group4&)";
+}
+
+} // end anonymous namespace
+
+
+int main()
+{
+#ifdef USING_CPP11_LAMBDA_EXPRESSIONS
+
+  // test lambda operators
+  int a = 1;
+  //std::cout << "(_1 + _2) (3,4):    " << (_1 + _2) (3,4)      << std::endl;
+  result_stream << ([] (int a, int b) -> int { return a + b; }(3,4));
+  check_result("7");
+
+  //std::cout << "(_1 + 1)  (3,4):    " << (_1 + 1)  (3,4)      << std::endl;
+  result_stream << ([] (int a, int) -> int { return a + 1; }(3,4));
+  check_result("4");
+
+  //std::cout << "(_2 + 1)  (3,4):    " << (_2 + 1)  (3,4)      << std::endl;
+  result_stream << ([] (int, int b) -> int { return b + 1; }(3,4));
+  check_result("5");
+
+  //std::cout << "(2 + _1)  (3,4):    " << (2 + _1)  (3,4)      << std::endl;
+  result_stream << ([] (int a, int) -> int { return 2 + a; }(3,4));
+  check_result("5");
+
+  //std::cout << "(2 + _2)  (3,4):    " << (2 + _2)  (3,4)      << std::endl;
+  result_stream << ([] (int, int b) -> int { return 2 + b; }(3,4));
+  check_result("6");
+
+  //std::cout << "(_1+_2*_3)(1,2,3):  " << (_1+_2*_3)(1,2,3)    << std::endl;
+  result_stream << ([] (int a, int b, int c) -> int { return a + b*c; }(1,2,3));
+  check_result("7");
+
+  //std::cout << "((++_1)*2)(1):      " << ((++_1)*2)(1)        << std::endl;
+  result_stream << ([] (int a) -> int { return ++a * 2; }(1));
+  check_result("4");
+
+  //std::cout << "((++_1)*2)(a):      " << ((++_1)*2)(a);
+  //std::cout << "; a: "                << a                    << std::endl;
+  result_stream << ([] (int x) -> int { return ++x * 2; }(a)) << " " << a;
+  check_result("4 1");
+
+  // gcc can't compile libsigc++ lambda expressions with sigc::ref() parameters.
+  // See https://bugzilla.gnome.org/show_bug.cgi?id=669128
+  //  std::cout << "((++_1)*2)(ref(a)): " << ((++_1)*2)(sigc::ref(a));
+  //  std::cout << "; a: "                << a                    << std::endl;
+  result_stream << ([] (std::reference_wrapper<int> x) -> int { return ++x * 2; }(std::ref(a)));
+  result_stream << " " << a;
+  check_result("4 2");
+  result_stream << ([] (int& x) -> int { return ++x * 2; }(a));
+  result_stream << " " << a;
+  check_result("6 3");
+
+  //std::cout << "((++(*_1))*2)(&a):  " << ((++(*_1))*2)(&a);
+  //std::cout << "; a: "                << a                    << std::endl;
+  result_stream << ([] (int* x) -> int { return ++(*x) * 2; }(&a));
+  result_stream << " " << a;
+  check_result("8 4");
+
+  //  std::cout << "((--(*(&_1)))*2)(ref(a)): " << ((--(*(&_1)))*2)(sigc::ref(a));
+  //  std::cout << "; a: "                << a                    << std::endl;
+  result_stream << ([] (std::reference_wrapper<int> x) -> int { return --(*(&x)) * 2; }(std::ref(a)));
+  result_stream << " " << a;
+  check_result("6 3");
+  result_stream << ([] (int& x) -> int { return --(*(&x)) * 2; }(a));
+  result_stream << " " << a;
+  check_result("4 2");
+
+  //std::cout << "(-_1)     (-5):     " << (-_1)     (-5)       << std::endl;
+  result_stream << ([] (int x) -> int { return -x; }(-5));
+  check_result("5");
+
+  //std::cout << "(var(&a)[0])():     " << (sigc::var(&a)[0])() << std::endl;
+  result_stream << ([&a]() -> int { return a; }());
+  check_result("2");
+
+  //std::cout << "(_1[_2])    (&a,0): " << (_1[_2])    (&a,0)   << std::endl;
+  result_stream << ([] (int* x, int y) -> int { return x[y]; }(&a,0));
+  check_result("2");
+
+  //std::cout << "(*_1=_2)    (&a,1): " << (*_1=_2)    (&a,1)   << std::endl;
+  result_stream << ([] (int* x, int y) -> int { *x = y; return *x; }(&a,1));
+  check_result("1");
+
+  // c++ restrictions:
+  // - ref() must be used to indicate that the value shall not be copied
+  // - constant() is used to create a lambda and delay execution of "std::cout << 1"
+  // - var() is used to create a lambda that holds a reference and is interchangable with ref() in lambda operator expressions
+  // - cannot use std::endl without much hackery because it is defined as a template function
+  // - cannot use "\n" without var() because arrays cannot be copied
+  //  (sigc::ref(std::cout) << sigc::constant(1) << sigc::var("\n"))();
+  [&result_stream](){ result_stream << 1 << "\n"; }();
+  check_result("1\n");
+
+  //(sigc::ref(std::cout) << _1 << std::string("\n"))("hello world");
+  [&result_stream](const char* a){ result_stream << a << std::string("\n"); }("hello world");
+  check_result("hello world\n");
+
+  //(sigc::ref(std::cout) << sigc::static_cast_<int>(_1) << std::string("\n"))(1.234);
+  [&result_stream](double a){ result_stream << static_cast<int>(a) << std::string("\n"); }(1.234);
+  check_result("1\n");
+
+  //  (sigc::var(std::cout) << 1 << sigc::var("\n"))();
+  [&result_stream](){ result_stream << 1 << "\n"; }();
+  check_result("1\n");
+
+  //(sigc::var(std::cout) << _1 << std::string("\n"))("hello world");
+  [&result_stream](const char* a){ result_stream << a << std::string("\n"); }("hello world");
+  check_result("hello world\n");
+
+  // auto-disconnect
+  // Here's an area where the libsigc++ lambda expressions has an advantage.
+  // It can be more difficult to auto-disconnect slots without them.
+  sigc::slot<void, std::ostringstream&> sl1;
+  {
+    struct printable_book : public book
+    {
+      explicit printable_book(const std::string& name) : book(name) {}
+      void operator()(std::ostringstream& stream) { stream << *this << "\n"; }
+    };
+    //book guest_book("karl");
+    printable_book printable_guest_book("karl");
+    // sl1 = (sigc::var(std::cout) << sigc::ref(guest_book) << sigc::var("\n"));
+    // sl1 = [&result_stream, &guest_book](){ result_stream << guest_book << "\n"; }; // no auto-disconnect
+    // sl1 = printable_guest_book; // no auto-disconnect, no error; a copy is stored in sl1
+    sl1 = sigc::mem_fun(printable_guest_book, &printable_book::operator());
+    sl1(result_stream);
+    check_result("karl\n");
+
+  } // auto-disconnect
+
+  sl1(result_stream);
+  check_result("");
+
+  // test group adaptor, here replaced by std::bind
+  bar the_bar;
+  //std::cout << (sigc::group(&foo, _1, _2)) (1, 2) << std::endl;
+  result_stream << std::bind(&foo, std::placeholders::_1, std::placeholders::_2)(1, 2);
+  check_result("foo(int 1, int 2)6");
+
+  //std::cout << (sigc::group(&foo, _2, _1)) (1, 2) << std::endl;
+  result_stream << std::bind(&foo, std::placeholders::_2, std::placeholders::_1)(1, 2);
+  check_result("foo(int 2, int 1)9");
+
+  //std::cout << (sigc::group(sigc::mem_fun(&bar::test), _1, _2, _3)) (sigc::ref(the_bar), 1, 2) << std::endl;
+  result_stream << std::bind(std::mem_fn(&bar::test), std::placeholders::_1,
+    std::placeholders::_2, std::placeholders::_3)(std::ref(the_bar), 1, 2);
+  check_result("bar::test(int 1, int 2)6");
+
+  // same functionality as bind
+  //std::cout << (sigc::group(&foo, _1, 2))  (1)    << std::endl;
+  result_stream << std::bind(&foo, std::placeholders::_1, 2)(1);
+  check_result("foo(int 1, int 2)6");
+
+  //std::cout << (sigc::group(&foo, 1, 2))   ()     << std::endl;
+  result_stream << std::bind(&foo, 1, 2)();
+  check_result("foo(int 1, int 2)6");
+
+  //(sigc::group(sigc::ptr_fun(&foo_void), 1)) ();
+  std::bind(sigc::ptr_fun(&foo_void), 1)();
+  check_result("foo_void(int 1)");
+
+  // auto-disconnect
+  sigc::slot<void> sl2;
+  {
+    book guest_book("karl");
+    //sl2 = sigc::group(&egon, sigc::ref(guest_book));
+    // sl2 = [&egon, &guest_book] () { egon(guest_book); }; // no auto-disconnect
+    // sl2 = std::bind(&egon, std::ref(guest_book));        // does not compile (gcc 4.6.3)
+    sl2 = sigc::bind(&egon, sigc::ref(guest_book));
+    sl2();
+    check_result("egon(string 'karl')");
+
+    //std::cout << static_cast<std::string&>(guest_book) << std::endl;
+    result_stream << static_cast<std::string&>(guest_book);
+    check_result("egon was here");
+
+  } // auto-disconnect
+
+  sl2();
+  check_result("");
+
+  // same functionality as hide
+  //std::cout << (sigc::group(&foo, _1, _2)) (1,2,3) << std::endl;
+  result_stream << std::bind(&foo, std::placeholders::_1, std::placeholders::_2)(1,2,3);
+  check_result("foo(int 1, int 2)6");
+
+  //(sigc::group(sigc::ptr_fun(&foo_void), _2)) (1, 2);
+  std::bind(&foo_void, std::placeholders::_2)(1, 2);
+  check_result("foo_void(int 2)");
+
+  // same functionality as compose
+  //std::cout << (sigc::group(&foo, sigc::group(&foo, _1, _2), _3)) (1,2,3) << std::endl;
+  result_stream << std::bind(&foo, std::bind(&foo, std::placeholders::_1, std::placeholders::_2),
+    std::placeholders::_3)(1,2,3);
+  check_result("foo(int 1, int 2)foo(int 6, int 3)27");
+
+  // same functionality as retype
+  //std::cout << (sigc::group(&foo, sigc::static_cast_<int>(_1), 2)) (1.234) << std::endl;
+  result_stream << ([&foo] (double x) -> int { return foo(static_cast<int>(x), 2); }(1.234));
+  check_result("foo(int 1, int 2)6");
+
+  // Code examples with C++11 lambda expressions and std::bind, which can replace
+  // libsigc++ examples in the documentation of libsigc++ lambdas and sigc::group.
+  // -----------------------------------------------------------------------------
+
+  //--- sigc++/adaptors/lambda/macros/base.h.m4
+
+  //std::cout << sigc::_1(10,20,30); // returns 10
+  result_stream << ([] (int x, int, int) -> int { return x; }(10,20,30));
+  check_result("10");
+
+  //std::cout << sigc::_2(10,20,30); // returns 20
+  result_stream << ([] (int, int y, int) -> int { return y; }(10,20,30));
+  check_result("20");
+
+  //std::cout << (sigc::_1 + 5)(3); // returns (3 + 5)
+  result_stream << ([] (int x) -> int { return x + 5; }(3));
+  check_result("8");
+
+  //std::cout << (sigc::_1 * sigc::_2)(7,10); // returns (7 * 10)
+  result_stream << ([] (int x, int y) -> int { return x * y; }(7,10));
+  check_result("70");
+
+  //int main(int argc, char* argv[])
+  //{
+  //  int data;
+  //  sigc::signal<int> readValue;
+  //
+  //  readValue.connect(sigc::var(data));
+  //
+  //  data = 3;
+  //  std::cout << readValue() << std::endl; //Prints 3.
+  //
+  //  data = 5;
+  //  std::cout << readValue() << std::endl; //Prints 5.
+  //}
+  {
+    int data;
+    sigc::signal<int> readValue;
+
+    readValue.connect([&data] () -> int { return data; });
+
+    data = 3;
+    result_stream << readValue();
+    check_result("3");
+
+    data = 5;
+    result_stream << readValue();
+    check_result("5");
+  }
+
+  //--- sigc++/adaptors/lambda/macros/group.h.m4
+
+  // argument binding ...
+  //sigc::group(&foo,10,sigc::_1)(20); //fixes the first argument and calls foo(10,20)
+  std::bind(&foo_group1, 10, std::placeholders::_1)(20);
+  check_result("foo_group1(int 10, int 20)");
+
+  //sigc::group(&foo,sigc::_1,30)(40); //fixes the second argument and calls foo(40,30)
+  std::bind(&foo_group1, std::placeholders::_1, 30)(40);
+  check_result("foo_group1(int 40, int 30)");
+
+  // argument reordering ...
+  //sigc::group(&foo,sigc::_2,sigc::_1)(1,2); //calls foo(2,1)
+  std::bind(&foo_group1, std::placeholders::_2, std::placeholders::_1)(1,2);
+  check_result("foo_group1(int 2, int 1)");
+
+  // argument hiding ...
+  //sigc::group(&foo,sigc::_1,sigc::_2)(1,2,3); //calls foo(1,2)
+  std::bind(&foo_group1, std::placeholders::_1, std::placeholders::_2)(1,2,3);
+  check_result("foo_group1(int 1, int 2)");
+
+  // functor composition ...
+  //sigc::group(&foo,sigc::_1,sigc::group(&bar,sigc::_2))(1,2); //calls foo(1,bar(2))
+  std::bind(&foo_group1,  std::placeholders::_1, std::bind(&bar_group1, std::placeholders::_2))(1,2);
+  check_result("bar_group1(int 2)foo_group1(int 1, int 4)");
+
+  // algebraic expressions ...
+  // sigc::group(&foo,sigc::_1*sigc::_2,sigc::_1/sigc::_2)(6,3); //calls foo(6*3,6/3)
+  [&foo_group1] (int x, int y) { foo_group1(x*y, x/y); }(6,3);
+  check_result("foo_group1(int 18, int 2)");
+
+  {
+    sigc::signal<void,int,int> some_signal;
+    //some_signal.connect(sigc::group(&foo,sigc::_2));
+    //some_signal.connect(std::bind(&foo_group2, std::placeholders::_2)); // does not compile (gcc 4.6.3)
+    some_signal.connect([&foo_group2](int, int y) { foo_group2(y); });
+    some_signal.emit(1,2);
+    check_result("foo_group2(int 2)");
+  }
+
+  {
+    int some_int = 0;
+    sigc::signal<void> some_signal;
+    //some_signal.connect(sigc::group(&foo,sigc::ref(some_int)));
+    //some_signal.connect(std::bind(&foo_group3, std::ref(some_int))); // does not compile (gcc 4.6.3)
+    //some_signal.connect(sigc::bind(&foo_group3, sigc::ref(some_int))); // compiles, but we prefer std::bind() or C++11 lambda
+    some_signal.connect([&foo_group3, &some_int](){ foo_group3(some_int); });
+    some_signal.emit();
+    result_stream << some_int;
+    check_result("foo_group3(int 0)1");
+  }
+
+  {
+    struct bar : public sigc::trackable {} some_bar;
+    sigc::signal<void> some_signal;
+    {
+      bar_group4 some_bar;
+      //some_signal.connect(sigc::group(&foo,sigc::ref(some_bar)));
+      // disconnected automatically if some_bar goes out of scope
+      //some_signal.connect([&foo_group4, &some_bar](){ foo_group4(some_bar); }); // no auto-disconnect
+      some_signal.connect(sigc::bind(&foo_group4, sigc::ref(some_bar)));
+      some_signal.emit();
+      check_result("foo_group4(bar_group4&)");
+    }
+    some_signal.emit();
+    check_result("");
+  }
+
+#else // not USING_CPP11_LAMBDA_EXPRESSIONS
+  std::cout << "The compiler capabilities don't allow test of C++11 lambda expressions." << std::endl;
+#endif
+
+  return result_ok ? EXIT_SUCCESS : EXIT_FAILURE;
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]