[libsigc++2/variadic_bind2: 56/68] exception_catch_functor::operator():
- From: Murray Cumming <murrayc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsigc++2/variadic_bind2: 56/68] exception_catch_functor::operator():
- Date: Tue, 1 Mar 2016 21:48:25 +0000 (UTC)
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]