[libsigc++2/variadic] track_obj.h.m4: Make this variadic.
- From: Murray Cumming <murrayc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsigc++2/variadic] track_obj.h.m4: Make this variadic.
- Date: Thu, 14 Jan 2016 20:45:47 +0000 (UTC)
commit 4abd4d6a559671173a48eb4cbf6a1e5ca631cdc0
Author: Murray Cumming <murrayc murrayc com>
Date: Thu Jan 14 21:32:10 2016 +0100
track_obj.h.m4: Make this variadic.
This uses a tuple_for_each_const<>() utility taken from here:
https://github.com/murraycu/murrayc-tuple-utils/tree/master/tuple-utils
for the visit_each() specialization.
sigc++/adaptors/macros/track_obj.h.m4 | 165 +++++++++++++-------------------
sigc++/filelist.am | 1 +
sigc++/tuple_for_each_const.h | 76 +++++++++++++++
tests/Makefile.am | 2 +
tests/test_tuple_for_each.cc | 166 +++++++++++++++++++++++++++++++++
5 files changed, 312 insertions(+), 98 deletions(-)
---
diff --git a/sigc++/adaptors/macros/track_obj.h.m4 b/sigc++/adaptors/macros/track_obj.h.m4
index b957eae..38a831f 100644
--- a/sigc++/adaptors/macros/track_obj.h.m4
+++ b/sigc++/adaptors/macros/track_obj.h.m4
@@ -19,94 +19,12 @@ divert(-1)
include(template.macros.m4)
-dnl track_obj_functor[2..CALL_SIZE]. $1 is assumed to be >= 2.
-define([TRACK_OBJECT_FUNCTOR],[dnl
-/** track_obj_functor$1 wraps a functor and stores $1 references to trackable objects.
- * Use the convenience function track_obj() to create an instance of track_obj_functor$1.
- *
- * @tparam T_functor The type of functor to wrap.dnl
-FOR(1,$1,[
- * @tparam T_obj%1 The type of a trackable object.])
- *
- * @newin{2,4}
- *
- * @ingroup track_obj
- */
-template <typename T_functor, LOOP(typename T_obj%1, $1)>
-class track_obj_functor$1 : public track_obj_functor1<T_functor, T_obj1>
-{
-public:
- /** Constructs a track_obj_functor$1 object that wraps the passed functor and
- * stores references to the passed trackable objects.
- * @param _A_func Functor.dnl
-FOR(1,$1,[
- * @param _A_obj%1 Trackable object.])
- */
- track_obj_functor$1(const T_functor& _A_func, LOOP(const T_obj%1& _A_obj%1, $1))
- : track_obj_functor1<T_functor, T_obj1>(_A_func, _A_obj1)FOR(2,$1,[[, ]obj%1_(_A_obj%1)]) {}
-
-#ifndef DOXYGEN_SHOULD_SKIP_THIS
-//protected:
- // public, so that visit_each() can access it.dnl
-FOR(2,$1,[
- const_limit_reference<T_obj%1> obj%1_;])
-#endif /* DOXYGEN_SHOULD_SKIP_THIS */
-
-}; // end class track_obj_functor$1
-
-])dnl end TRACK_OBJECT_FUNCTOR
-
-define([TRACK_OBJECT_VISIT_EACH],[dnl
-//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::track_obj_functor$1 performs a functor
- * on the functor and on the trackable object instances stored in the
- * sigc::track_obj_functor$1 object.
- *
- * @newin{2,4}
- *
- * @ingroup track_obj
- */
-template <typename T_functor, LOOP(typename T_obj%1, $1)>
-struct visitor<track_obj_functor$1<T_functor, LOOP(T_obj%1, $1)> >
-{
- template <typename T_action>
- static void do_visit_each(const T_action& _A_action,
- const track_obj_functor$1<T_functor, LOOP(T_obj%1, $1)>& _A_target)
- {
- sigc::visit_each(_A_action, _A_target.functor_);dnl
-FOR(1,$1,[
- sigc::visit_each(_A_action, _A_target.obj%1_);])
- }
-};
-
-])dnl end TRACK_OBJECT_VISIT_EACH
-
-define([TRACK_OBJECT],[dnl
-/** Creates an adaptor of type sigc::track_obj_functor$1 which wraps a functor.
- * @param _A_func Functor that shall be wrapped.dnl
-FOR(1,$1,[
- * @param _A_obj%1 Trackable object.])
- * @return Adaptor that executes _A_func() on invocation.
- *
- * @newin{2,4}
- *
- * @ingroup track_obj
- */
-template <typename T_functor, LOOP(typename T_obj%1, $1)>
-inline track_obj_functor$1<T_functor, LOOP(T_obj%1, $1)>
-track_obj(const T_functor& _A_func, LOOP(const T_obj%1& _A_obj%1, $1))
-{
- return track_obj_functor$1<T_functor, LOOP(T_obj%1, $1)>
- (_A_func, LOOP(_A_obj%1, $1));
-}
-
-])dnl end TRACK_OBJECT
divert(0)dnl
_FIREWALL([ADAPTORS_TRACK_OBJ])
#include <sigc++/adaptors/adaptor_trait.h>
#include <sigc++/limit_reference.h>
+#include <sigc++/tuple_for_each_const.h>
namespace sigc {
@@ -139,30 +57,30 @@ namespace sigc {
* @ingroup adaptors
*/
-/** track_obj_functor1 wraps a functor and stores a reference to a trackable object.
- * Use the convenience function track_obj() to create an instance of track_obj_functor1.
+/** track_obj_functor wraps a functor and stores a reference to a trackable object.
+ * Use the convenience function track_obj() to create an instance of track_obj_functor.
*
* @tparam T_functor The type of functor to wrap.
- * @tparam T_obj1 The type of a trackable object.
+ * @tparam T_obj The types of the trackable objects.
*
* @newin{2,4}
*
* @ingroup track_obj
*/
-template <typename T_functor, typename T_obj1>
-class track_obj_functor1 : public adapts<T_functor>
+template <typename T_functor, typename... T_obj>
+class track_obj_functor : public adapts<T_functor>
{
public:
typedef typename adapts<T_functor>::adaptor_type adaptor_type;
typedef typename adaptor_type::result_type result_type;
- /** Constructs a track_obj_functor1 object that wraps the passed functor and
- * stores a reference to the passed trackable object.
+ /** Constructs a track_obj_functor object that wraps the passed functor and
+ * stores a reference to the passed trackable objects.
* @param _A_func Functor.
- * @param _A_obj1 Trackable object.
+ * @param _A_obj Trackable objects.
*/
- track_obj_functor1(const T_functor& _A_func, const T_obj1& _A_obj1)
- : adapts<T_functor>(_A_func), obj1_(_A_obj1) {}
+ track_obj_functor(const T_functor& _A_func, const T_obj&... _A_obj)
+ : adapts<T_functor>(_A_func), obj_(_A_obj...) {}
/** Invokes the wrapped functor.
* @return The return value of the functor invocation.
@@ -186,17 +104,68 @@ public:
#ifndef DOXYGEN_SHOULD_SKIP_THIS
//protected:
// public, so that visit_each() can access it.
- const_limit_reference<T_obj1> obj1_;
+ std::tuple<const_limit_reference<T_obj>...> obj_;
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
-}; // end class track_obj_functor1
+}; // end class track_obj_functor
-FOR(2,CALL_SIZE,[[TRACK_OBJECT_FUNCTOR(%1)]])dnl
#ifndef DOXYGEN_SHOULD_SKIP_THIS
-FOR(1,CALL_SIZE,[[TRACK_OBJECT_VISIT_EACH(%1)]])dnl
+//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::track_obj_functor performs a functor
+ * on the functor and on the trackable object instances stored in the
+ * sigc::track_obj_functor object.
+ *
+ * @newin{2,4}
+ *
+ * @ingroup track_obj
+ */
+template <typename T_functor, typename... T_obj>
+struct visitor<track_obj_functor<T_functor, T_obj...>>
+{
+ template <typename T_action>
+ static void do_visit_each(const T_action& _A_action,
+ const track_obj_functor<T_functor, T_obj...>& _A_target)
+ {
+ sigc::visit_each(_A_action, _A_target.functor_);
+
+ //Call sigc::visit_each(_A_action, element) on each element in the
+ //_A_target.obj_ tuple:
+ sigc::tuple_for_each_const<TrackObjVisitForEach>(_A_target.obj_, _A_action);
+ }
+
+private:
+ template<typename T_element, typename T_action>
+ struct TrackObjVisitForEach
+ {
+ static
+ void
+ visit(const T_element& element, const T_action& action)
+ {
+ sigc::visit_each(action, element);
+ }
+ };
+};
#endif // DOXYGEN_SHOULD_SKIP_THIS
-FOR(1,CALL_SIZE,[[TRACK_OBJECT(%1)]])dnl
+
+/** Creates an adaptor of type sigc::track_obj_functor which wraps a functor.
+ * @param _A_func Functor that shall be wrapped.
+ * @param _A_obj Trackable objects.
+ * @return Adaptor that executes _A_func() on invocation.
+ *
+ * @newin{2,4}
+ *
+ * @ingroup track_obj
+ */
+template <typename T_functor, typename... T_obj>
+inline decltype(auto)
+track_obj(const T_functor& _A_func, const T_obj&... _A_obj)
+{
+ return track_obj_functor<T_functor, T_obj...>
+ (_A_func, _A_obj...);
+}
+
} /* namespace sigc */
diff --git a/sigc++/filelist.am b/sigc++/filelist.am
index 5aaea9e..267cc90 100644
--- a/sigc++/filelist.am
+++ b/sigc++/filelist.am
@@ -58,6 +58,7 @@ sigc_public_h = \
tuple_cat.h \
tuple_cdr.h \
tuple_end.h \
+ tuple_for_each_const.h \
tuple_start.h \
type_traits.h \
visit_each.h \
diff --git a/sigc++/tuple_for_each_const.h b/sigc++/tuple_for_each_const.h
new file mode 100644
index 0000000..cac485e
--- /dev/null
+++ b/sigc++/tuple_for_each_const.h
@@ -0,0 +1,76 @@
+/* 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_FOR_EACH_CONST_H_
+#define _SIGC_TUPLE_FOR_EACH_CONST_H_
+
+#include <tuple>
+
+namespace sigc
+{
+
+namespace {
+
+template<template<typename> class T_visitor, std::size_t index, typename... T_extras>
+struct tuple_for_each_const_impl
+{
+ template<typename T>
+ static
+ void
+ tuple_for_each_const(const T& t, T_extras... extras) {
+ using element_type = typename std::tuple_element<index, T>::type;
+ T_visitor<element_type>::visit(std::get<index>(t), extras...);
+
+ tuple_for_each_const_impl<T_visitor, index - 1, T_extras...>::tuple_for_each_const(t, extras...);
+ }
+};
+
+template<template<typename> class T_visitor, typename... T_extras>
+struct tuple_for_each_const_impl<T_visitor, 0, T_extras...>
+{
+ template<typename T>
+ static
+ void
+ tuple_for_each_const(const T& t, T_extras... extras) {
+ constexpr std::size_t index = 0;
+
+ using element_type = typename std::tuple_element<index, T>::type;
+ T_visitor<element_type>::visit(std::get<index>(t), extras...);
+ }
+};
+
+} //anonymous namespace
+
+/**
+ * Get a tuple with each element having the transformed value of the element
+ * in the original tuple.
+ *
+ * @tparam T_visitor should be a template that has a static visit() method.
+ * @tparam T the tuple type.
+ * @tparam T_extras the types of any extra arguments to pass to @e T_Visitor's visit() method.
+ * @param t The tuple whose elements should be visited.
+ * @param extras Any extra arguments to pass to @e T_Visitor's visit() method.
+ */
+template<template<typename> class T_visitor, typename T, typename... T_extras>
+void
+tuple_for_each_const(const T& t, T_extras... extras) {
+ constexpr auto size = std::tuple_size<T>::value;
+ tuple_for_each_const_impl<T_visitor, size - 1, T_extras...>::tuple_for_each_const(t, extras...);
+}
+
+} //namespace sigc
+
+#endif //_SIGC_TUPLE_FOR_EACH_CONST_H_
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 1061ca8..bbf641b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -52,6 +52,7 @@ check_PROGRAMS = \
test_tuple_cat \
test_tuple_cdr \
test_tuple_end \
+ test_tuple_for_each \
test_tuple_start \
test_visit_each
@@ -91,5 +92,6 @@ test_track_obj_SOURCES = test_track_obj.cc $(sigc_test_util)
test_tuple_cat_SOURCES = test_tuple_cat.cc $(sigc_test_util)
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_visit_each_SOURCES = test_visit_each.cc $(sigc_test_util)
diff --git a/tests/test_tuple_for_each.cc b/tests/test_tuple_for_each.cc
new file mode 100644
index 0000000..e2558d6
--- /dev/null
+++ b/tests/test_tuple_for_each.cc
@@ -0,0 +1,166 @@
+/* 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_for_each.h>
+#include <sigc++/tuple_for_each_const.h>
+#include <utility>
+#include <cstdlib>
+#include <cassert>
+//#include <typeinfo>
+#include <iostream>
+
+template <class T_element_from>
+class for_each_simple
+{
+public:
+ static
+ void
+ visit(const T_element_from& from) {
+ std::cout << "for_each_simple(): " << std::to_string(from) << std::endl;
+ }
+};
+
+void test_tuple_for_each_same_types()
+{
+ {
+ auto t_original = std::make_tuple(1, 2, 3);
+ sigc::tuple_for_each_const<for_each_simple>(t_original);
+ }
+
+ {
+ auto t_original = std::make_tuple(1, (double)2.1f, 3);
+ sigc::tuple_for_each_const<for_each_simple>(t_original);
+ }
+}
+
+template <class T_element_from>
+class for_each_simple_with_extras
+{
+public:
+ static
+ void
+ visit(const T_element_from& from, int extra1, const std::string& extra2) {
+ std::cout << "for_each_simple_with_extras(): from=" <<
+ std::to_string(from) <<
+ ", extra1: " << extra1 <<
+ ", extra2: " << extra2 << std::endl;
+ }
+};
+
+void test_tuple_for_each_same_types_with_extras()
+{
+ {
+ auto t_original = std::make_tuple(1, (double)2.1f, 3);
+ sigc::tuple_for_each_const<for_each_simple_with_extras>(t_original, 89, "eightynine");
+ }
+}
+
+template <class T_element_from>
+class for_each_simple_with_nonconst_extras
+{
+public:
+ static
+ void
+ visit(const T_element_from& from, int& extra) {
+ extra += (int)from;
+ }
+};
+
+void test_tuple_for_each_same_types_with_nonconst_extras()
+{
+ {
+ auto t_original = std::make_tuple(1, (double)2.1f, 3);
+ int extra = 0;
+
+ //TODO: avoid the need to specify the tuple type (decltype(t_original).
+ // It can't be at the end (or can't it?) because we have T_extras... at the end.
+ //TODO: avoid the need to specify that the int should be passed by reference?
+ sigc::tuple_for_each_const<for_each_simple_with_nonconst_extras, decltype(t_original), int&>(t_original,
extra);
+ //std::cout << "extra: " << extra << std::endl;
+ assert(extra == 6);
+ }
+}
+
+//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 visitor_with_specializations;
+
+//An int will be converted to a std::string:
+template <>
+class visitor_with_specializations<int>
+{
+public:
+ static
+ void
+ visit(const int& from) {
+ std::cout << "visitor_with_specializations::visit(): " << std::to_string(from) << std::endl;
+ }
+};
+
+//A double will be converted to a char:
+template <>
+class visitor_with_specializations<double>
+{
+public:
+ static
+ void
+ visit(const double& from) {
+ std::cout << "visitor_with_specializations::visit(): " << std::to_string(from)[0] << std::endl;
+ }
+};
+
+//A std::string will be converted to an int:
+template <>
+class visitor_with_specializations<std::string>
+{
+public:
+ static
+ void
+ visit(const std::string& from) {
+ std::cout << "visitor_with_specializations::visit(): " << std::stoi(from) << std::endl;
+ }
+};
+
+void test_tuple_for_each_multiple_types()
+{
+ auto t_original = std::make_tuple(1, (double)2.1f, std::string("3"));
+ sigc::tuple_for_each_const<visitor_with_specializations>(t_original);
+}
+
+template <class T_element_from>
+class for_each_nonconst
+{
+public:
+ static
+ void
+ visit(T_element_from& from) {
+ from *= 2;
+ //Or, for instance, call a non-const method on from.
+ }
+};
+
+int main()
+{
+ test_tuple_for_each_same_types();
+ test_tuple_for_each_same_types_with_extras();
+ test_tuple_for_each_same_types_with_nonconst_extras();
+
+ test_tuple_for_each_multiple_types();
+
+ return EXIT_SUCCESS;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]