delegate works now also with move only types (close #272)

This commit is contained in:
Michele Caini
2019-07-02 14:49:49 +02:00
parent 842988c2ad
commit 46150a2da4
3 changed files with 36 additions and 8 deletions
+1
View File
@@ -23,6 +23,7 @@
- iterator based each with a couple of iterators passed from outside (use bitmask + has)
* stable component handle that isn't affected by reallocations
* multi component registry::remove and some others?
* can I use opaque connection also for the emitter?
* built-in support for dual (or N-) buffering
TODO
+8 -8
View File
@@ -101,16 +101,16 @@ class delegate;
*/
template<typename Ret, typename... Args>
class delegate<Ret(Args...)> {
using proto_fn_type = Ret(const void *, std::tuple<Args...>);
using proto_fn_type = Ret(const void *, std::tuple<Args &&...>);
template<auto Function, std::size_t... Index>
void connect(std::index_sequence<Index...>) ENTT_NOEXCEPT {
data = nullptr;
fn = [](const void *, std::tuple<Args...> args) -> Ret {
fn = [](const void *, std::tuple<Args &&...> args) -> Ret {
// Ret(...) makes void(...) eat the return values to avoid errors
static_assert(std::is_invocable_r_v<Ret, decltype(Function), std::tuple_element_t<Index, std::tuple<Args...>>...>);
// Ret(...) allows void(...) to eat return values and avoid errors
return Ret(std::invoke(Function, std::get<Index>(args)...));
return Ret(std::invoke(Function, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
};
}
@@ -118,7 +118,7 @@ class delegate<Ret(Args...)> {
void connect(Type *value_or_instance, std::index_sequence<Index...>) ENTT_NOEXCEPT {
data = value_or_instance;
fn = [](const void *payload, std::tuple<Args...> args) -> Ret {
fn = [](const void *payload, std::tuple<Args &&...> args) -> Ret {
Type *curr = nullptr;
if constexpr(std::is_const_v<Type>) {
@@ -127,9 +127,9 @@ class delegate<Ret(Args...)> {
curr = static_cast<Type *>(const_cast<void *>(payload));
}
// Ret(...) makes void(...) eat the return values to avoid errors
static_assert(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, std::tuple_element_t<Index, std::tuple<Args...>>...>);
// Ret(...) allows void(...) to eat return values and avoid errors
return Ret(std::invoke(Candidate, curr, std::get<Index>(args)...));
return Ret(std::invoke(Candidate, curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(args))...));
};
}
@@ -232,7 +232,7 @@ public:
*/
Ret operator()(Args... args) const {
ENTT_ASSERT(fn);
return fn(data, std::forward_as_tuple(args...));
return fn(data, std::forward_as_tuple(std::forward<Args>(args)...));
}
/**
+27
View File
@@ -1,3 +1,4 @@
#include <memory>
#include <gtest/gtest.h>
#include <entt/signal/delegate.hpp>
@@ -9,6 +10,14 @@ int curried_function(const int *i, int j) {
return *i+j;
}
int non_const_reference(int &i) {
return i *= i;
}
int move_only_type(std::unique_ptr<int> ptr) {
return *ptr;
}
struct delegate_functor {
int operator()(int i) {
return i+i;
@@ -235,6 +244,24 @@ TEST(Delegate, ConstInstance) {
ASSERT_EQ(delegate, entt::delegate<int(int)>{});
}
TEST(Delegate, NonConstReference) {
entt::delegate<int(int &)> delegate;
delegate.connect<&non_const_reference>();
int value = 3;
ASSERT_EQ(delegate(value), value);
ASSERT_EQ(value, 9);
}
TEST(Delegate, MoveOnlyType) {
entt::delegate<int(std::unique_ptr<int>)> delegate;
auto ptr = std::make_unique<int>(3);
delegate.connect<&move_only_type>();
ASSERT_EQ(delegate(std::move(ptr)), 3);
ASSERT_FALSE(ptr);
}
TEST(Delegate, CurriedFunction) {
entt::delegate<int(int)> delegate;
const auto value = 3;