summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjell Ahlstedt <kjell.ahlstedt@bredband.net>2012-08-28 19:40:24 +0200
committerKjell Ahlstedt <kjell.ahlstedt@bredband.net>2012-08-28 19:40:24 +0200
commit41cf46e0fca8128abab298f54209d427a5a6c1b9 (patch)
tree9d3a460ff9b8c8916edda0d9510567d76473550b
parent50911ffcadaf483d3fe14078ed5153e55fc5985b (diff)
downloadsigc++-41cf46e0fca8128abab298f54209d427a5a6c1b9.tar.gz
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.
-rw-r--r--ChangeLog16
-rw-r--r--sigc++/adaptors/lambda/macros/base.h.m428
-rw-r--r--sigc++/adaptors/lambda/macros/group.h.m434
-rw-r--r--sigc++/functors/macros/functor_trait.h.m4110
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/test_cpp11_lambda.cc483
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;
+}