Skip to content

Commit b154e84

Browse files
rherilierkjellahl
authored andcommitted
signal_connect: Add helper functions to ease connecting functions or methods to signals
Those helper functions have 2 main usages: * avoid writing template parameters in case of method or function overloading; * wrap use of sigc::mem_fun or sigc::ptr_fun when possible. unsupported cases: * lambda functions; * std::function (or alike); * volatile functions; * const? volatile methods; * binding with sigc::bind.
1 parent 8181576 commit b154e84

File tree

9 files changed

+258
-0
lines changed

9 files changed

+258
-0
lines changed

sigc++/filelist.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ sigc_public_h = \
2727
scoped_connection.h \
2828
signal.h \
2929
signal_base.h \
30+
signal_connect.h \
3031
slot.h \
3132
trackable.h \
3233
tuple-utils/tuple_cdr.h \

sigc++/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ sigc_h_files = [
2525
'scoped_connection.h',
2626
'signal.h',
2727
'signal_base.h',
28+
'signal_connect.h',
2829
'slot.h',
2930
'trackable.h',
3031
'type_traits.h',

sigc++/sigc++.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
#include <sigc++/connection.h>
120120
#include <sigc++/scoped_connection.h>
121121
#include <sigc++/trackable.h>
122+
#include <sigc++/signal_connect.h>
122123
#include <sigc++/adaptors/adaptors.h>
123124
#include <sigc++/functors/functors.h>
124125

sigc++/signal_base.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,22 @@ struct SIGC_API signal_impl_holder
281281
* a @ref sigc::slot<T_return(T_arg...)> "sigc::slot"
282282
* and connected to a signal. See @ref slot "Slots" and
283283
* @ref sigc::signal_with_accumulator::connect() "sigc::signal::connect()".
284+
*
285+
* Use @ref sigc::signal_connect() to connect a method or function to a signal
286+
* without having to explicitly write the required template parameters in case
287+
* of method or function overloading.
288+
*
289+
* @code
290+
* sigc::signal<void(int)> sig;
291+
* void fun(int);
292+
* void fun(double);
293+
* sig.connect(sigc::ptr_fun<void, int>(fun));
294+
* // or more simply:
295+
* sigc::signal_connect(sig, fun);
296+
* @endcode
297+
*
298+
* It can also be used as a replacement for calling signal::connect() with a
299+
* sigc::mem_fun() or a sigc::ptr_fun().
284300
*/
285301

286302
// TODO: When we can break ABI, let signal_base derive from trackable again,

sigc++/signal_connect.h

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright 2024, The libsigc++ Development Team
3+
*
4+
* This library is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU Lesser General Public
6+
* License as published by the Free Software Foundation; either
7+
* version 2.1 of the License, or (at your option) any later version.
8+
*
9+
* This library is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
* Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public
15+
* License along with this library; if not, write to the Free Software
16+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17+
*
18+
*/
19+
20+
#ifndef SIGC_SIGNAL_CONNECT_H
21+
#define SIGC_SIGNAL_CONNECT_H
22+
23+
#include <sigc++/signal.h>
24+
#include <sigc++/functors/ptr_fun.h>
25+
#include <sigc++/functors/mem_fun.h>
26+
27+
namespace sigc
28+
{
29+
30+
/** Connect a function to a signal
31+
* @param signal The signal to connect to.
32+
* @param fun The function that should be wrapped.
33+
* @return A connection.
34+
*
35+
* @ingroup signal
36+
*/
37+
template<typename T_return, typename... T_arg>
38+
inline connection
39+
signal_connect(signal<T_return(T_arg...)>& signal, T_return (*fun)(T_arg...))
40+
{
41+
return signal.connect(ptr_fun<T_return, T_arg...>(fun));
42+
}
43+
44+
/** Connect a non-const method to a signal
45+
* @param signal The signal to connect to.
46+
* @param obj Reference to object instance the functor should operate on.
47+
* @param fun Pointer to method that should be wrapped.
48+
* @return A connection.
49+
*
50+
* @ingroup signal
51+
*/
52+
template<typename T_return, typename T_obj, typename... T_arg>
53+
inline connection
54+
signal_connect(signal<T_return(T_arg...)>& signal, /**/ T_obj& obj, T_return (T_obj::*fun)(T_arg...))
55+
{
56+
return signal.connect(mem_fun<T_return, T_obj, T_obj, T_arg...>(obj, fun));
57+
}
58+
59+
/** Connect a const method to a signal
60+
* @param signal The signal to connect to.
61+
* @param obj Reference to object instance the functor should operate on.
62+
* @param fun Pointer to method that should be wrapped.
63+
* @return A connection.
64+
*
65+
* @ingroup signal
66+
*/
67+
#if SIGC_MSC
68+
/* MSVC needs to distinguish object's class and method's class (using the
69+
* template parameter T_obj2) to avoid raising error C2672 (no matching
70+
* overloaded function found) when signal_connect(...) is called with a
71+
* const object.
72+
*/
73+
template<typename T_return, typename T_obj, typename T_obj2, typename... T_arg>
74+
inline connection
75+
signal_connect(signal<T_return(T_arg...)>& signal, /*const*/ T_obj& obj, T_return (T_obj2::*fun)(T_arg...) const)
76+
{
77+
return signal.connect(mem_fun<T_return, T_obj, T_obj, T_arg...>(obj, fun));
78+
}
79+
#else
80+
template<typename T_return, typename T_obj, typename... T_arg>
81+
inline connection
82+
signal_connect(signal<T_return(T_arg...)>& signal, /*const*/ T_obj& obj, T_return (T_obj::*fun)(T_arg...) const)
83+
{
84+
return signal.connect(mem_fun<T_return, T_obj, T_obj, T_arg...>(obj, fun));
85+
}
86+
#endif
87+
88+
} /* namespace sigc */
89+
90+
#endif /* SIGC_SIGNAL_CONNECT_H */
91+

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ set (TEST_SOURCE_FILES
4242
test_rvalue_ref.cc
4343
test_scoped_connection.cc
4444
test_signal.cc
45+
test_signal_connect.cc
4546
test_signal_move.cc
4647
test_size.cc
4748
test_slot.cc

tests/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ check_PROGRAMS = \
4949
test_rvalue_ref \
5050
test_scoped_connection \
5151
test_signal \
52+
test_signal_connect \
5253
test_signal_move \
5354
test_size \
5455
test_slot \
@@ -95,6 +96,7 @@ test_retype_return_SOURCES = test_retype_return.cc $(sigc_test_util)
9596
test_rvalue_ref_SOURCES = test_rvalue_ref.cc $(sigc_test_util)
9697
test_scoped_connection_SOURCES = test_scoped_connection.cc $(sigc_test_util)
9798
test_signal_SOURCES = test_signal.cc $(sigc_test_util)
99+
test_signal_connect_SOURCES = test_signal_connect.cc $(sigc_test_util)
98100
test_signal_move_SOURCES = test_signal_move.cc $(sigc_test_util)
99101
test_size_SOURCES = test_size.cc $(sigc_test_util)
100102
test_slot_SOURCES = test_slot.cc $(sigc_test_util)

tests/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ test_programs = [
3131
[[], 'test_rvalue_ref', ['test_rvalue_ref.cc', 'testutilities.cc']],
3232
[[], 'test_scoped_connection', ['test_scoped_connection.cc', 'testutilities.cc']],
3333
[[], 'test_signal', ['test_signal.cc', 'testutilities.cc']],
34+
[[], 'test_signal_connect', ['test_signal_connect.cc', 'testutilities.cc']],
3435
[[], 'test_signal_move', ['test_signal_move.cc', 'testutilities.cc']],
3536
[[], 'test_size', ['test_size.cc', 'testutilities.cc']],
3637
[[], 'test_slot', ['test_slot.cc', 'testutilities.cc']],

tests/test_signal_connect.cc

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/* Copyright 2024, The libsigc++ Development Team
2+
* Assigned to public domain. Use as you wish without restriction.
3+
*/
4+
5+
#include "testutilities.h"
6+
#include <sigc++/trackable.h>
7+
#include <sigc++/signal_connect.h>
8+
9+
namespace
10+
{
11+
12+
TestUtilities* util = nullptr;
13+
std::ostringstream result_stream;
14+
15+
void
16+
fun(int i)
17+
{
18+
result_stream << "fun(int " << i << ")";
19+
}
20+
21+
[[maybe_unused]]
22+
void
23+
fun(double d)
24+
{
25+
result_stream << "fun(double " << d << ")";
26+
}
27+
28+
struct foo : public sigc::trackable
29+
{
30+
void fun_nonconst(int i)
31+
{
32+
result_stream << "foo::fun_nonconst(int " << i << ")";
33+
}
34+
35+
void fun_nonconst(double d)
36+
{
37+
result_stream << "foo::fun_nonconst(double " << d << ")";
38+
}
39+
40+
void fun_const(int i) const
41+
{
42+
result_stream << "foo::fun_const(int " << i << ")";
43+
}
44+
45+
void fun_const(double d) const
46+
{
47+
result_stream << "foo::fun_const(double " << d << ")";
48+
}
49+
};
50+
51+
struct bar : public sigc::trackable
52+
{
53+
void fun_nonconst(int i, int j)
54+
{
55+
result_stream << "bar::fun_nonconst(int " << i << ", int " << j << ")";
56+
}
57+
58+
void fun_nonconst(int i, double j)
59+
{
60+
result_stream << "bar::fun_nonconst(int " << i << ", double " << j << ")";
61+
}
62+
63+
void fun_const(int i, int j) const
64+
{
65+
result_stream << "bar::fun_const(int " << i << ", int " << j << ")";
66+
}
67+
68+
void fun_const(int i, double j) const
69+
{
70+
result_stream << "bar::fun_const(int " << i << ", double " << j << ")";
71+
}
72+
};
73+
74+
void
75+
test_signal_connect_fun()
76+
{
77+
sigc::signal<void(int)> signal;
78+
79+
sigc::signal_connect(signal, &fun);
80+
81+
signal.emit(42);
82+
util->check_result(result_stream, "fun(int 42)");
83+
}
84+
85+
void
86+
test_signal_connect_method_nonconst()
87+
{
88+
sigc::signal<void(int)> signal;
89+
foo f;
90+
91+
sigc::signal_connect(signal, f, &foo::fun_nonconst);
92+
93+
signal.emit(42);
94+
util->check_result(result_stream, "foo::fun_nonconst(int 42)");
95+
}
96+
97+
void
98+
test_signal_connect_method_const()
99+
{
100+
sigc::signal<void(int)> signal;
101+
foo f;
102+
103+
sigc::signal_connect(signal, f, &foo::fun_const);
104+
105+
signal.emit(42);
106+
util->check_result(result_stream, "foo::fun_const(int 42)");
107+
}
108+
109+
void
110+
test_signal_connect_method_const_with_const_object()
111+
{
112+
sigc::signal<void(int)> signal;
113+
const foo f;
114+
115+
sigc::signal_connect(signal, f, &foo::fun_const);
116+
117+
signal.emit(42);
118+
util->check_result(result_stream, "foo::fun_const(int 42)");
119+
}
120+
121+
void
122+
test_signal_connect_method()
123+
{
124+
test_signal_connect_method_nonconst();
125+
test_signal_connect_method_const();
126+
test_signal_connect_method_const_with_const_object();
127+
}
128+
129+
} // end anonymous namespace
130+
131+
int
132+
main(int argc, char* argv[])
133+
{
134+
util = TestUtilities::get_instance();
135+
136+
if (!util->check_command_args(argc, argv))
137+
return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
138+
139+
test_signal_connect_fun();
140+
141+
test_signal_connect_method();
142+
143+
return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
144+
}

0 commit comments

Comments
 (0)