[libsigc++2/variadic_bind2: 56/68] exception_catch_functor::operator():



commit b3093fb058db5c40a91730bc32076b2f6318d0d2
Author: Murray Cumming <murrayc murrayc com>
Date:   Fri Jan 15 10:31:09 2016 +0100

    exception_catch_functor::operator():
    
    Remove the unnecessary operator()() overload.
    This did need me to change the test code so that it doesn't try to
    provide a catch function that returns something, but that seems
    more correct anyway.

 sigc++/.gitignore                  |    1 -
 sigc++/adaptors/bind.h             |  316 +++++++++++++++++++++++++++++++
 sigc++/adaptors/exception_catch.h  |   13 --
 sigc++/adaptors/macros/bind.h.m4   |  363 ------------------------------------
 sigc++/filelist.am                 |    7 +-
 sigc++/tuple_transform_each.h      |  156 +++++++++++++++
 tests/Makefile.am                  |    2 +
 tests/test_exception_catch.cc      |   19 ++-
 tests/test_tuple_cat.cc            |    4 +
 tests/test_tuple_for_each.cc       |   14 ++
 tests/test_tuple_transform_each.cc |  200 ++++++++++++++++++++
 11 files changed, 713 insertions(+), 382 deletions(-)
---
diff --git a/sigc++/.gitignore b/sigc++/.gitignore
index 384ef53..d8c2879 100644
--- a/sigc++/.gitignore
+++ b/sigc++/.gitignore
@@ -1,4 +1,3 @@
 /limit_reference.h
-/adaptors/bind.h
 /adaptors/retype.h
 /functors/mem_fun.h
diff --git a/sigc++/adaptors/bind.h b/sigc++/adaptors/bind.h
new file mode 100644
index 0000000..d2d66fc
--- /dev/null
+++ b/sigc++/adaptors/bind.h
@@ -0,0 +1,316 @@
+#ifndef _SIGC_ADAPTORS_BIND_H_
+#define _SIGC_ADAPTORS_BIND_H_
+#include <sigc++/adaptors/adaptor_trait.h>
+#include <sigc++/adaptors/bound_argument.h>
+#include <tuple>
+#include <sigc++/tuple_start.h>
+#include <sigc++/tuple_end.h>
+#include <sigc++/tuple_transform_each.h>
+#include <sigc++/tuple_for_each_const.h>
+
+//TODO: See comment in functor_trait.h.
+#if defined(nil) && defined(SIGC_PRAGMA_PUSH_POP_MACRO)
+  #define SIGC_NIL_HAS_BEEN_PUSHED 1
+  #pragma push_macro("nil")
+  #undef nil
+#endif
+
+namespace sigc {
+
+
+/** @defgroup bind bind(), bind_return()
+ * sigc::bind() alters an arbitrary functor by fixing arguments to certain values.
+ * Up to 7 arguments can be bound at a time.
+ * For single argument binding, overloads of sigc::bind() are provided that let you
+ * specify the zero-based position of the argument to fix with the first template parameter.
+ * (A value of @p -1 fixes the last argument so sigc::bind<-1>() gives the same result as sigc::bind().)
+ * The types of the arguments can optionally be specified if not deduced.
+ *
+ * @par Examples:
+ * @code
+ * void foo(int, int, int);
+ * // single argument binding ...
+ * sigc::bind(&foo,1)(2,3);     //fixes the last (third) argument and calls foo(2,3,1)
+ * sigc::bind<-1>(&foo,1)(2,3); //same as bind(&foo,1)(2,3) (calls foo(2,3,1))
+ * sigc::bind<0>(&foo,1)(2,3);  //fixes the first argument and calls foo(1,2,3)
+ * sigc::bind<1>(&foo,1)(2,3);  //fixes the second argument and calls foo(2,1,3)
+ * sigc::bind<2>(&foo,1)(2,3);  //fixes the third argument and calls foo(2,3,1)
+ * // multi argument binding ...
+ * sigc::bind(&foo,1,2)(3);     //fixes the last two arguments and calls foo(3,1,2)
+ * sigc::bind(&foo,1,2,3)();    //fixes all three arguments and calls foo(1,2,3)
+ * @endcode
+ *
+ * The functor sigc::bind() returns can be passed into
+ * sigc::signal::connect() directly.
+ *
+ * @par Example:
+ * @code
+ * sigc::signal<void> some_signal;
+ * void foo(int);
+ * some_signal.connect(sigc::bind(&foo,1));
+ * @endcode
+ *
+ * sigc::bind_return() alters an arbitrary functor by
+ * fixing its return value to a certain value.
+ *
+ * @par Example:
+ * @code
+ * void foo();
+ * std::cout << sigc::bind_return(&foo, 5)(); // calls foo() and returns 5
+ * @endcode
+ *
+ * You can bind references to functors by passing the objects through
+ * the std::ref() helper function.
+ *
+ * @par Example:
+ * @code
+ * int some_int;
+ * sigc::signal<void> some_signal;
+ * void foo(int&);
+ * some_signal.connect(sigc::bind(&foo, std::ref(some_int)));
+ * @endcode
+ *
+ * If you bind an object of a sigc::trackable derived type to a functor
+ * by reference, a slot assigned to the bind adaptor is cleared automatically
+ * when the object goes out of scope.
+ *
+ * @par Example:
+ * @code
+ * struct bar : public sigc::trackable {} some_bar;
+ * sigc::signal<void> some_signal;
+ * void foo(bar&);
+ * some_signal.connect(sigc::bind(&foo, std::ref(some_bar)));
+ *   // disconnected automatically if some_bar goes out of scope
+ * @endcode
+ *
+ * @ingroup adaptors
+ */
+
+namespace internal
+{
+
+template <class T_element>
+struct TransformEachInvoker
+{
+  //We take T_element as non-const because invoke() is not const.
+  static
+  decltype(auto)
+  transform(T_element& element) {
+    return element.invoke();
+  }
+};
+
+} //namespace internal
+
+/** Adaptor that binds arguments to the wrapped functor.
+ * Use the convenience function sigc::bind() to create an instance of sigc::bind_functor.
+ *
+ * The following template arguments are used:
+ * - @e I_location Zero-based position of the argument to fix (@p -1 for the last argument).
+ * - @e T_bound Types of the bound argument.
+ * - @e T_functor Type of the functor to wrap.
+ *
+ * @ingroup bind
+ */
+template <int I_location, class T_functor, class... T_bound>
+struct bind_functor : public adapts<T_functor>
+{
+  typedef typename adapts<T_functor>::adaptor_type adaptor_type;
+  typedef typename adaptor_type::result_type  result_type;
+
+  /** Invokes the wrapped functor passing on the arguments.
+   * bound_ is passed as the next argument.
+   * @param _A_arg Arguments to be passed on to the functor.
+   * @return The return value of the functor invocation.
+   */
+  template <class... T_arg>
+  decltype(auto)
+  operator()(T_arg... _A_arg)
+    {
+      //For instance, if I_location is 1, and _A_arg has 4 arguments,
+      //we would want to call operator() with (_A_arg0, bound, _A_arg1, _A_arg2).
+      
+      using tuple_type_args = std::tuple<type_trait_pass_t<T_arg>...>;
+      auto t_args = std::make_tuple(_A_arg...);
+      constexpr auto t_args_size = std::tuple_size<tuple_type_args>::value;
+      
+      auto t_start = tuple_start<I_location>(t_args);
+      auto t_bound = tuple_transform_each<internal::TransformEachInvoker>(bound_);
+      auto t_end = tuple_end<t_args_size - I_location>(t_args);
+      auto t_with_bound = std::tuple_cat(t_start, t_bound, t_end);
+
+      //TODO: Avoid needing to specify the type when calling operator()?
+      using t_type_start = typename tuple_type_start<tuple_type_args, I_location>::type;
+      using t_type_bound = std::tuple<type_trait_pass_t<typename unwrap_reference<T_bound>::type>...>;
+
+      //using tuple_type_args_pass = std::tuple<type_trait_pass_t<T_arg>...>;
+      //using t_type_end = typename tuple_type_end<tuple_type_args_pass  t_args_size - I_location>::type;
+      using t_type_end = typename tuple_type_end<tuple_type_args, t_args_size - I_location>::type;
+      using t_type_with_bound = typename tuple_type_cat<typename tuple_type_cat<t_type_start, 
t_type_bound>::type, t_type_end>::type;
+
+      const auto seq = std::make_index_sequence<std::tuple_size<decltype(t_with_bound)>::value>();
+      return call_functor_operator_parentheses<t_type_with_bound>(
+        t_with_bound, seq);
+    }
+
+  /** Constructs a bind_functor object that binds an argument to the passed functor.
+   * @param _A_func Functor to invoke from operator()().
+   * @param _A_bound Argument to bind to the functor.
+   */
+  bind_functor(type_trait_take_t<T_functor> _A_func, type_trait_take_t<T_bound>... _A_bound)
+    : adapts<T_functor>(_A_func), bound_(_A_bound...)
+    {}
+
+  //TODO: Should this be private?
+  /// The arguments bound to the functor.
+  std::tuple<bound_argument<T_bound>...> bound_;
+
+private:
+  template<class T_specific, class T, std::size_t... Is>
+  decltype(auto)
+  call_functor_operator_parentheses(T& tuple,
+    std::index_sequence<Is...>)
+  {
+    return this->functor_.SIGC_WORKAROUND_OPERATOR_PARENTHESES<typename std::tuple_element<Is, 
T_specific>::type...>(std::get<Is>(tuple)...);
+  }
+};
+
+
+/** Adaptor that binds argument(s) to the wrapped functor.
+ * This template specialization fixes the last argument(s) of the wrapped functor.
+ *
+ * @ingroup bind
+ */
+template <class T_functor, class... T_type>
+struct bind_functor<-1, T_functor, T_type...> : public adapts<T_functor>
+{
+  typedef typename adapts<T_functor>::adaptor_type adaptor_type;
+  typedef typename adaptor_type::result_type  result_type;
+
+  /** Invokes the wrapped functor passing on the arguments.
+   * bound_ is passed as the next argument.
+   * @param _A_arg Arguments to be passed on to the functor.
+   * @return The return value of the functor invocation.
+   */
+  template <class... T_arg>
+  decltype(auto)
+  operator()(T_arg... _A_arg)
+    {
+      //For instance, if _A_arg has 4 arguments,
+      //we would want to call operator() with (_A_arg0, _A_arg1, _A_arg2, bound).
+      
+      auto t_args = std::make_tuple(_A_arg...);
+      auto t_bound = tuple_transform_each<internal::TransformEachInvoker>(bound_);
+      auto t_with_bound = std::tuple_cat(t_args, t_bound);
+
+      //TODO: Avoid needing to specify the type when calling operator()?
+      using t_type_args = std::tuple<type_trait_pass_t<T_arg>...>;
+      using t_type_bound = std::tuple<type_trait_pass_t<typename unwrap_reference<T_type>::type>...>;
+      using t_type_with_bound = typename tuple_type_cat<t_type_args, t_type_bound>::type;
+
+      const auto seq = std::make_index_sequence<std::tuple_size<decltype(t_with_bound)>::value>();
+      return call_functor_operator_parentheses<t_type_with_bound>(t_with_bound, seq);
+    }
+
+  /** Constructs a bind_functor object that binds an argument to the passed functor.
+   * @param _A_func Functor to invoke from operator()().
+   * @param _A_bound Arguments to bind to the functor.
+   */
+  bind_functor(type_trait_take_t<T_functor> _A_func, type_trait_take_t<T_type>... _A_bound)
+    : adapts<T_functor>(_A_func), bound_(_A_bound...)
+    {}
+
+  /// The argument bound to the functor.
+  std::tuple<bound_argument<T_type>...> bound_;
+
+private:
+  template<class T_specific, class T, std::size_t... Is>
+  decltype(auto)
+  call_functor_operator_parentheses(T& tuple,
+    std::index_sequence<Is...>)
+  {
+    return this->functor_.SIGC_WORKAROUND_OPERATOR_PARENTHESES<typename std::tuple_element<Is, 
T_specific>::type...>(std::get<Is>(tuple)...);
+  }
+};
+
+namespace {
+
+//TODO: Avoid duplication with TrackObjVisitForEach in track_obj.h
+template<typename T_element>
+struct TupleVisitorVisitEach
+{
+  template<typename T_action>
+  static
+  void
+  visit(const T_element& element, const T_action& action)
+  {
+     sigc::visit_each(action, element);
+  }
+};
+
+} //anonymous namespace
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+//template specialization of visitor<>::do_visit_each<>(action, functor):
+/** Performs a functor on each of the targets of a functor.
+ * The function overload for sigc::bind_functor performs a functor on the
+ * functor and on the object instances stored in the sigc::bind_functor object.
+ *
+ * @ingroup bind
+ */
+template <class T_functor, class... T_type>
+struct visitor<bind_functor<-1, T_functor, T_type...> >
+{
+  template <typename T_action>
+  static void do_visit_each(const T_action& _A_action,
+                            const bind_functor<-1, T_functor, T_type...>& _A_target)
+  {
+    sigc::visit_each(_A_action, _A_target.functor_);
+
+    sigc::tuple_for_each_const<TupleVisitorVisitEach>(_A_target.bound_, _A_action);
+  }
+};
+#endif //DOXYGEN_SHOULD_SKIP_THIS
+
+/** Creates an adaptor of type sigc::bind_functor which binds the passed argument to the passed functor.
+ * The optional template argument @e I_location specifies the zero-based
+ * position of the argument to be fixed (@p -1 stands for the last argument).
+ *
+ * @param _A_func Functor that should be wrapped.
+ * @param _A_b1 Argument to bind to @e _A_func.
+ * @return Adaptor that executes @e _A_func with the bound argument on invokation.
+ *
+ * @ingroup bind
+ */
+template <int I_location, class T_functor, class... T_bound>
+inline decltype(auto)
+bind(const T_functor& _A_func, T_bound... _A_b)
+{
+  return bind_functor<I_location, T_functor, T_bound...>
+           (_A_func, _A_b...);
+}
+
+
+/** Creates an adaptor of type sigc::bind_functor which fixes the last arguments of the passed functor.
+ * This function overload fixes the last arguments of @e _A_func.
+ *
+ * @param _A_func Functor that should be wrapped.
+ * @param _A_b Arguments to bind to @e _A_func.
+ * @return Adaptor that executes _A_func with the bound argument on invokation.
+ *
+ * @ingroup bind
+ */
+template <class T_functor, class... T_type>
+inline decltype(auto)
+bind(const T_functor& _A_func, T_type... _A_b)
+{ return bind_functor<-1, T_functor, T_type...>(_A_func, _A_b...);
+}
+
+
+} /* namespace sigc */
+
+#ifdef SIGC_NIL_HAS_BEEN_PUSHED
+  #undef SIGC_NIL_HAS_BEEN_PUSHED
+  #pragma pop_macro("nil")
+#endif
+#endif /* _SIGC_ADAPTORS_BIND_H_ */
diff --git a/sigc++/adaptors/exception_catch.h b/sigc++/adaptors/exception_catch.h
index 992ffd7..1ea7c3b 100644
--- a/sigc++/adaptors/exception_catch.h
+++ b/sigc++/adaptors/exception_catch.h
@@ -99,10 +99,6 @@ struct exception_catch_functor<T_functor, T_catcher, void> : public adapts<T_fun
   typedef void result_type;
   typedef typename adapts<T_functor>::adaptor_type adaptor_type;
 
-  void
-  operator()();
-
-
   template <class... T_arg>
   decltype(auto)
   operator()(T_arg... _A_a)
@@ -127,15 +123,6 @@ struct exception_catch_functor<T_functor, T_catcher, void> : public adapts<T_fun
     T_catcher catcher_;
 };
 
-template <class T_functor, class T_catcher>
-void exception_catch_functor<T_functor, T_catcher, void>::operator()()
-  {
-    try
-      { this->functor_(); } // I don't understand why void return doesn't work here (Martin)
-    catch (...)
-      { this->catcher_(); }
-  }
-
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
 //template specialization of visitor<>::do_visit_each<>(action, functor):
 template <class T_functor, class T_catcher, class T_return>
diff --git a/sigc++/filelist.am b/sigc++/filelist.am
index e1c8c90..581496b 100644
--- a/sigc++/filelist.am
+++ b/sigc++/filelist.am
@@ -26,11 +26,9 @@ functors_built_cc =
 functors_built_h = mem_fun.h
 
 # Adaptors (adaptors/)
-adaptors_m4 = bind.h.m4 \
-             retype.h.m4
+adaptors_m4 = retype.h.m4
 adaptors_built_cc =
-adaptors_built_h = bind.h \
-                   retype.h
+adaptors_built_h = retype.h
 
 # Combine all the above parts with right directories prefixed
 sigc_m4 = $(base_m4:%=macros/%) \
@@ -58,6 +56,7 @@ sigc_public_h =                               \
        tuple_end.h \
        tuple_for_each_const.h \
        tuple_start.h \
+       tuple_transform_each.h \
        type_traits.h                   \
        visit_each.h                    \
        adaptors/adaptor_base.h \
diff --git a/sigc++/tuple_transform_each.h b/sigc++/tuple_transform_each.h
new file mode 100644
index 0000000..d64fe85
--- /dev/null
+++ b/sigc++/tuple_transform_each.h
@@ -0,0 +1,156 @@
+/* Copyright (C) 2016 Murray Cumming
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/
+ */
+
+#ifndef _SIGC_TUPLE_TRANSFORM_EACH_H_
+#define _SIGC_TUPLE_TRANSFORM_EACH_H_
+
+#include <sigc++/tuple_cat.h>
+#include <sigc++/tuple_cdr.h>
+#include <sigc++/tuple_start.h>
+#include <sigc++/tuple_end.h>
+#include <type_traits>
+
+namespace sigc
+{
+
+/*
+namespace {
+
+template<typename T, template<typename> class T_transformer, std::size_t index>
+struct tuple_type_transform_each_impl
+{
+private:
+  using from_element_type = typename std::tuple_element<index, T>::type;
+
+  using to_element_type =
+    typename 
std::result_of<decltype(&T_transformer<from_element_type>::transform)(from_element_type&)>::type;
+
+  using t_element_type = std::tuple<to_element_type>;
+
+  using t_type_start = typename tuple_type_start<T, index>::type;
+
+  using t_type_end = typename tuple_type_end<T, std::tuple_size<T>::value - index - 1>::type;
+
+  using t_type_with_transformed_element =
+    typename tuple_type_cat<
+      typename tuple_type_cat<t_type_start, t_element_type>::type,
+      t_type_end>::type;
+
+public:
+  using type = typename tuple_type_transform_each_impl<t_type_with_transformed_element, T_transformer, index 
- 1>::type;
+};
+
+template<typename T, template<typename> class T_transformer>
+struct tuple_type_transform_each_impl<T, T_transformer, 0>
+{
+private:
+  static constexpr std::size_t index = 0;
+  using from_element_type = typename std::tuple_element<index, T>::type;
+  using to_element_type = typename 
std::result_of<decltype(&T_transformer<from_element_type>::transform)(from_element_type&)>::type;
+  using t_element_type = std::tuple<to_element_type>;
+
+  using t_type_end = typename tuple_type_end<T, std::tuple_size<T>::value - index - 1>::type;
+
+  using t_type_with_transformed_element =
+    typename tuple_type_cat<t_element_type, t_type_end>::type;
+
+public:
+  using type = t_type_with_transformed_element;
+};
+
+} //anonymous namespace
+*/
+
+/**
+ * Get a tuple with each element having the transformed value of the element
+ * in the original tuple.
+ */
+/*
+template<typename T, template<typename> class T_transformer>
+struct tuple_type_transform_each
+{
+  using type = typename tuple_type_transform_each_impl<T, T_transformer, std::tuple_size<T>::value - 
1>::type;
+};
+*/
+
+namespace {
+
+template<template<typename> class T_transformer, std::size_t index>
+struct tuple_transform_each_impl
+{
+  //TODO: Avoid the need to pass t_original all the way into the recursion?
+  template<typename T_current, typename T_original>
+  static
+  decltype(auto)
+  tuple_transform_each(T_current& t, T_original& t_original) {
+    using element_type = typename std::tuple_element<index, T_current>::type;
+
+    auto& from = std::get<index>(t_original);
+    const auto element = T_transformer<element_type>::transform(from);
+    const auto t_element = std::make_tuple(element);
+    
+    const auto t_start = tuple_start<index>(t);
+
+    constexpr auto size = std::tuple_size<T_current>::value;
+
+    //t_end's elements will be copies of the elements in t, so this method's
+    //caller won't see the changes made in the subsequent call of
+    //tuple_transform_each() on those copies. That's why we pass t_original
+    //through too, so we can modify that directly.
+    //the const version (tuple_transform_each_const()) doesn't have to worry
+    //about this, though avoiding copying would be more efficient.
+    const auto t_end = tuple_end<size - index - 1>(t);
+
+    auto t_with_transformed_element =
+      std::tuple_cat(t_start, t_element, t_end);
+    return tuple_transform_each_impl<T_transformer, index - 1>::tuple_transform_each(
+      t_with_transformed_element, t_original);
+  }
+};
+
+template<template<typename> class T_transformer>
+struct tuple_transform_each_impl<T_transformer, 0>
+{
+  template<typename T_current, typename T_original>
+  static
+  decltype(auto)
+  tuple_transform_each(T_current& t, T_original& t_original) {
+    constexpr std::size_t index = 0;
+
+    using element_type = typename std::tuple_element<index, T_original>::type;
+    const auto element = T_transformer<element_type>::transform(std::get<index>(t_original));
+    const auto tuple_element = std::make_tuple(element);
+    const auto tuple_rest = tuple_cdr(t);
+    return std::tuple_cat(tuple_element, tuple_rest);
+  }
+};
+
+} //anonymous namespace
+
+/**
+ * Get a tuple with each element having the transformed value of the element
+ * in the original tuple.
+ */
+template<template<typename> class T_transformer, typename T>
+decltype(auto)
+tuple_transform_each(T& t) {
+  constexpr auto size = std::tuple_size<std::remove_reference_t<T>>::value;
+  return tuple_transform_each_impl<T_transformer, size - 1>::tuple_transform_each(t, t);
+}
+
+} //namespace sigc
+
+#endif //_SIGC_TUPLE_TRANSFORM_EACH_H_
diff --git a/tests/Makefile.am b/tests/Makefile.am
index da8d1de..09ae62e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -55,6 +55,7 @@ check_PROGRAMS = \
   test_tuple_end \
   test_tuple_for_each \
   test_tuple_start \
+  test_tuple_transform_each \
   test_visit_each
 
 TESTS = $(check_PROGRAMS)
@@ -96,4 +97,5 @@ test_tuple_cdr_SOURCES       = test_tuple_cdr.cc $(sigc_test_util)
 test_tuple_end_SOURCES       = test_tuple_end.cc $(sigc_test_util)
 test_tuple_for_each_SOURCES  = test_tuple_for_each.cc $(sigc_test_util)
 test_tuple_start_SOURCES     = test_tuple_start.cc $(sigc_test_util)
+test_tuple_transform_each_SOURCES = test_tuple_transform_each.cc $(sigc_test_util)
 test_visit_each_SOURCES      = test_visit_each.cc $(sigc_test_util)
diff --git a/tests/test_exception_catch.cc b/tests/test_exception_catch.cc
index f8f6e02..6ae7e51 100644
--- a/tests/test_exception_catch.cc
+++ b/tests/test_exception_catch.cc
@@ -63,6 +63,23 @@ struct my_catch
   }
 };
 
+struct my_catch_void
+{
+  void operator()()
+  {
+    try
+    {
+      throw;
+    }
+    catch (std::range_error e) // catch what types we know
+    {
+      result_stream << "caught " << e.what();
+    }
+
+    // all else continues out.
+  }
+};
+
 } // end anonymous namespace
 
 int main(int argc, char* argv[])
@@ -78,7 +95,7 @@ int main(int argc, char* argv[])
   result_stream << sigc::exception_catch(g(), my_catch())();
   util->check_result(result_stream, "g() caught out of range 1");
 
-  sigc::exception_catch(g_void(), my_catch())(); // void test
+  sigc::exception_catch(g_void(), my_catch_void())(); // void test
   util->check_result(result_stream, "g_void() caught out of range ");
 
   return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
diff --git a/tests/test_tuple_cat.cc b/tests/test_tuple_cat.cc
index 2300441..e5214ba 100644
--- a/tests/test_tuple_cat.cc
+++ b/tests/test_tuple_cat.cc
@@ -14,7 +14,11 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/
  */
 
+<<<<<<< Updated upstream
 #include <sigc++/tuple_cat.h>
+=======
+#include <sigc/tuple_cat.h>
+>>>>>>> Stashed changes
 #include <utility>
 #include <cstdlib>
 #include <cassert>
diff --git a/tests/test_tuple_for_each.cc b/tests/test_tuple_for_each.cc
index e2558d6..67156ae 100644
--- a/tests/test_tuple_for_each.cc
+++ b/tests/test_tuple_for_each.cc
@@ -142,6 +142,7 @@ void test_tuple_for_each_multiple_types()
   sigc::tuple_for_each_const<visitor_with_specializations>(t_original);
 }
 
+/*
 template <class T_element_from>
 class for_each_nonconst
 {
@@ -154,6 +155,17 @@ public:
   } 
 };
 
+void test_tuple_for_each_nonconst()
+{
+  auto t = std::make_tuple(1, 2, 3);
+  sigc::tuple_for_each<for_each_nonconst, decltype(t)&>(t);
+  std::cout << std::get<0>(t) << std::endl;
+  assert(std::get<0>(t) == 2);
+  assert(std::get<1>(t) == 4);
+  assert(std::get<2>(t) == 6);
+}
+*/
+
 int main()
 {
   test_tuple_for_each_same_types();
@@ -161,6 +173,8 @@ int main()
   test_tuple_for_each_same_types_with_nonconst_extras();
 
   test_tuple_for_each_multiple_types();
+
+  //test_tuple_for_each_nonconst();
       
   return EXIT_SUCCESS;
 }
diff --git a/tests/test_tuple_transform_each.cc b/tests/test_tuple_transform_each.cc
new file mode 100644
index 0000000..5501f3a
--- /dev/null
+++ b/tests/test_tuple_transform_each.cc
@@ -0,0 +1,200 @@
+/* Copyright (C) 2016 Murray Cumming
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/
+ */
+
+#include <sigc++/tuple_transform_each.h>
+#include <utility>
+#include <cstdlib>
+#include <cassert>
+
+
+template <class T_element_from>
+class transform_to_string
+{
+public:
+  static
+  decltype(auto)
+  transform(T_element_from& from) {
+    return std::to_string(from);
+  } 
+};
+
+/*
+void test_tuple_type_transform_each_same_types()
+{
+  using type_tuple_original = std::tuple<int, int>;
+  using type_tuple_transformed = sigc::tuple_type_transform_each<
+    type_tuple_original, transform_to_string>::type;
+  using type_tuple_expected = std::tuple<std::string, std::string>;
+
+  static_assert(std::is_same<type_tuple_transformed, type_tuple_expected>::value,
+    "unexpected tuple_transform_each()ed tuple type");
+}
+*/
+
+//In these tests, t_expected has elements all of the same type.
+void test_tuple_transform_each_same_types()
+{
+  {
+    auto t_original = std::make_tuple(1, 2, 3);
+    auto t_transformed = sigc::tuple_transform_each<transform_to_string>(t_original);
+    auto t_expected = std::make_tuple(std::string("1"), std::string("2"), std::string("3"));
+
+    static_assert(std::tuple_size<decltype(t_transformed)>::value == 3,
+      "unexpected tuple_transform_each()ed tuple size.");
+
+    assert(std::get<0>(t_transformed) == "1");
+    assert(std::get<1>(t_transformed) == "2");
+    assert(std::get<2>(t_transformed) == "3");
+
+    static_assert(std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
+      "unexpected transform_each()ed tuple type");
+  }
+
+  {
+    auto t_original = std::make_tuple(1, (double)2.1f, 3);
+    auto t_transformed = sigc::tuple_transform_each<transform_to_string>(t_original);
+    auto t_expected = std::make_tuple(std::string("1"), std::string("2"), std::string("3"));
+
+    static_assert(std::tuple_size<decltype(t_transformed)>::value == 3,
+      "unexpected tuple_transform_each()ed tuple size.");
+
+    assert(std::get<0>(t_transformed) == "1");
+    assert(std::get<1>(t_transformed).substr(0, 3) == "2.1");
+    assert(std::get<2>(t_transformed) == "3");
+
+    static_assert(std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
+      "unexpected transform_each()ed tuple type");
+  }
+}
+
+//The general template declaration.
+//We then provide specializations for each type,
+//so we can test having a different return value for each T_element_from type.
+template <class T_element_from>
+class transform_to_something;
+
+//An int will be converted to a std::string:
+template <>
+class transform_to_something<int>
+{
+public:
+  static
+  std::string
+  transform(int& from) {
+    return std::to_string(from);
+  } 
+};
+
+//A double will be converted to a char:
+template <>
+class transform_to_something<double>
+{
+public:
+  static
+  char
+  transform(double& from) {
+    return std::to_string(from)[0];
+  } 
+};
+
+//A std::string will be converted to an int:
+template <>
+class transform_to_something<std::string>
+{
+public:
+  static
+  int
+  transform(std::string& from) {
+    return std::stoi(from);
+  } 
+};
+
+/*
+void test_tuple_type_transform_each_multiple_types()
+{
+  using type_tuple_original = std::tuple<int, double, std::string>;
+  using type_tuple_transformed = sigc::tuple_type_transform_each<
+    type_tuple_original, transform_to_something>::type;
+  using type_tuple_expected = std::tuple<std::string, char, int>;
+
+  static_assert(std::is_same<type_tuple_transformed, type_tuple_expected>::value,
+    "unexpected tuple_transform_each()ed tuple type");
+}
+*/
+
+//In these tests, t_expected has elements of different types.
+void test_tuple_transform_each_multiple_types()
+{
+  auto t_original = std::make_tuple(1, (double)2.1f, std::string("3"));
+  auto t_transformed = sigc::tuple_transform_each<transform_to_something>(t_original);
+  auto t_expected = std::make_tuple(std::string("1"), '2', 3);
+
+  static_assert(std::tuple_size<decltype(t_transformed)>::value == 3,
+    "unexpected tuple_transform_each()ed tuple size.");
+
+  assert(std::get<0>(t_transformed) == "1");
+  assert(std::get<1>(t_transformed) == '2');
+  assert(std::get<2>(t_transformed) == 3);
+
+  static_assert(std::is_same<decltype(t_transformed), decltype(t_expected)>::value,
+    "unexpected transform_each()ed tuple type");
+}
+
+
+template <class T_element_from>
+class transform_each_nonconst
+{
+public:
+  static
+  int
+  transform(T_element_from& from) {
+    from *= 2;
+    //Or, for instance, call a non-const method on from.
+
+    return from * 10;
+  } 
+};
+
+void test_tuple_transform_each_nonconst()
+{
+  auto t = std::make_tuple(1, 2, 3);
+  auto t_transformed = sigc::tuple_transform_each<transform_each_nonconst>(t);
+
+  //Check that t was changed (from * 2):
+  assert(std::get<0>(t) == 2);
+  assert(std::get<1>(t) == 4);
+  assert(std::get<2>(t) == 6);
+
+  //Check that t_transformed has the expected values ( from * 2 * 10):
+  assert(std::get<0>(t_transformed) == 20);
+  assert(std::get<1>(t_transformed) == 40);
+  assert(std::get<2>(t_transformed) == 60);
+}
+
+
+int main()
+{
+  //test_tuple_type_transform_each_same_types();
+
+  //test_tuple_type_transform_each_multiple_types();
+
+  test_tuple_transform_each_same_types();
+  test_tuple_transform_each_multiple_types();
+
+  test_tuple_transform_each_nonconst();
+      
+  return EXIT_SUCCESS;
+}


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