Skip to content

Allow slots with rvalue reference parameters #74

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions sigc++/functors/slot.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ struct slot_call
static T_return call_it(slot_rep* rep, type_trait_take_t<T_arg>... a_)
{
auto typed_rep = static_cast<typed_slot_rep<T_functor>*>(rep);
return (*typed_rep->functor_).template operator()<type_trait_take_t<T_arg>...>(a_...);
return (*typed_rep->functor_).template operator()<type_trait_take_t<T_arg>...>(
std::forward<type_trait_take_t<T_arg>>(a_)...);
}

/** Forms a function pointer from call_it().
Expand Down Expand Up @@ -220,7 +221,7 @@ class slot<T_return(T_arg...)> : public slot_base
{
return std::invoke(sigc::internal::function_pointer_cast<call_type>(slot_base::rep_->call_),
slot_base::rep_,
a...);
std::forward<type_trait_take_t<T_arg>>(a)...);
}

return T_return();
Expand Down
10 changes: 7 additions & 3 deletions sigc++/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,9 @@ struct signal_emit<void, void, T_arg...>
if (slot.empty() || slot.blocked())
continue;

(sigc::internal::function_pointer_cast<call_type>(slot.rep_->call_))(slot.rep_, a...);
(sigc::internal::function_pointer_cast<call_type>(slot.rep_->call_))(
slot.rep_,
std::forward<type_trait_take_t<T_arg>>(a)...);
}
}
};
Expand Down Expand Up @@ -450,11 +452,13 @@ class signal_with_accumulator : public signal_base
decltype(auto) emit(type_trait_take_t<T_arg>... a) const
{
using emitter_type = internal::signal_emit<T_return, T_accumulator, T_arg...>;
return emitter_type::emit(impl_, a...);
return emitter_type::emit(impl_, std::forward<type_trait_take_t<T_arg>>(a)...);
}

/** Triggers the emission of the signal (see emit()). */
decltype(auto) operator()(type_trait_take_t<T_arg>... a) const { return emit(a...); }
decltype(auto) operator()(type_trait_take_t<T_arg>... a) const {
return emit(std::forward<type_trait_take_t<T_arg>>(a)...);
}

/** Creates a functor that calls emit() on this signal.
* @code
Expand Down
7 changes: 7 additions & 0 deletions sigc++/type_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ struct type_trait<const T_type&>
using take = const T_type&;
};

template<typename T_type>
struct type_trait<T_type&&>
{
using pass = T_type&&;
using take = T_type&&;
};

template<>
struct type_trait<void>
{
Expand Down
4 changes: 2 additions & 2 deletions tests/memleakcheck.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ for testprog in test_accum_iter test_accumulated test_bind test_bind_as_slot \
test_copy_invalid_slot test_cpp11_lambda test_custom test_disconnect \
test_disconnect_during_emit test_exception_catch test_hide \
test_limit_reference test_member_method_trait test_mem_fun test_ptr_fun \
test_retype test_retype_return test_signal test_signal_move test_size \
test_slot test_slot_disconnect test_slot_move test_trackable \
test_retype test_retype_return test_rvalue_ref test_signal test_signal_move \
test_size test_slot test_slot_disconnect test_slot_move test_trackable \
test_trackable_move test_track_obj test_tuple_cdr test_tuple_end \
test_tuple_for_each test_tuple_start test_tuple_transform_each \
test_visit_each test_visit_each_trackable test_weak_raw_ptr
Expand Down
1 change: 1 addition & 0 deletions tests/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ test_programs = [
[[], 'test_ptr_fun', ['test_ptr_fun.cc', 'testutilities.cc']],
[[], 'test_retype', ['test_retype.cc', 'testutilities.cc']],
[[], 'test_retype_return', ['test_retype_return.cc', 'testutilities.cc']],
[[], 'test_rvalue_ref', ['test_rvalue_ref.cc', 'testutilities.cc']],
[[], 'test_signal', ['test_signal.cc', 'testutilities.cc']],
[[], 'test_signal_move', ['test_signal_move.cc', 'testutilities.cc']],
[[], 'test_size', ['test_size.cc', 'testutilities.cc']],
Expand Down
55 changes: 55 additions & 0 deletions tests/test_rvalue_ref.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include "testutilities.h"
#include <iostream>
#include <sigc++/signal.h>

struct MoveableStruct {};

namespace
{
TestUtilities* util = nullptr;
std::ostringstream result_stream;

struct foo
{
void operator()(MoveableStruct &&x)
{
result_stream << "foo(MoveableStruct&&)";
}
};

} // end anonymous namespace

void
test_signal()
{
sigc::signal<void (MoveableStruct &&)> signal;
foo f;
signal.connect(f);
MoveableStruct x;
signal(std::move(x));
util->check_result(result_stream, "foo(MoveableStruct&&)");
}

void
test_slot()
{
sigc::slot<void (MoveableStruct &&)> slot;
foo f;
slot = f;
MoveableStruct x;
slot(std::move(x));
util->check_result(result_stream, "foo(MoveableStruct&&)");
}

int
main(int argc, char* argv[])
{
util = TestUtilities::get_instance();
if (!util->check_command_args(argc, argv))
return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;

test_signal();
test_slot();

return util->get_result_and_delete_instance() ? EXIT_SUCCESS : EXIT_FAILURE;
} // end main()