mirror of
https://github.com/ETLCPP/etl.git
synced 2026-04-30 19:09:10 +08:00
delegate: allow constructing from non-capturing lambdas
Signed-off-by: Benedek Kupper <kupper.benedek@gmail.com>
This commit is contained in:
parent
e9c2577d8e
commit
bfbb7259e1
@ -155,10 +155,23 @@ namespace etl
|
||||
|
||||
//*************************************************************************
|
||||
// Delete construction from rvalue reference lambda or functor.
|
||||
// Excludes non-capturing lambdas convertible to a function pointer.
|
||||
//*************************************************************************
|
||||
template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_same<etl::delegate<TReturn(TArgs...)>, TLambda>::value, void>>
|
||||
template <typename TLambda, typename = etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_same<etl::delegate<TReturn(TArgs...)>, TLambda>::value && !etl::is_convertible<TLambda, TReturn(*)(TArgs...)>::value, void>>
|
||||
ETL_CONSTEXPR14 delegate(TLambda&& instance) = delete;
|
||||
|
||||
//*************************************************************************
|
||||
// Construct from non-capturing rvalue lambda convertible to function pointer.
|
||||
// Converts to a function pointer to avoid storing a dangling pointer
|
||||
// to a destroyed temporary.
|
||||
//*************************************************************************
|
||||
template <typename TLambda, etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_reference<TLambda>::value && etl::is_convertible<TLambda, TReturn(*)(TArgs...)>::value, int> = 0>
|
||||
delegate(TLambda&& instance) ETL_NOEXCEPT
|
||||
{
|
||||
TReturn(*fp)(TArgs...) = static_cast<TReturn(*)(TArgs...)>(instance);
|
||||
assign(reinterpret_cast<void*>(fp), function_ptr_stub);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Create from function (Compile time).
|
||||
//*************************************************************************
|
||||
@ -189,6 +202,19 @@ namespace etl
|
||||
return delegate((void*)(&instance), const_lambda_stub<TLambda>);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
// Create from non-capturing rvalue lambda convertible to function pointer.
|
||||
// Converts to a function pointer to avoid storing a dangling pointer
|
||||
// to a destroyed temporary.
|
||||
//*************************************************************************
|
||||
template <typename TLambda, etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_reference<TLambda>::value && etl::is_convertible<TLambda, TReturn(*)(TArgs...)>::value, int> = 0>
|
||||
ETL_NODISCARD
|
||||
static delegate create(TLambda&& instance) ETL_NOEXCEPT
|
||||
{
|
||||
TReturn(*fp)(TArgs...) = static_cast<TReturn(*)(TArgs...)>(instance);
|
||||
return delegate(reinterpret_cast<void*>(fp), function_ptr_stub);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Create from instance method (Run time).
|
||||
//*************************************************************************
|
||||
@ -305,6 +331,18 @@ namespace etl
|
||||
assign((void*)(&instance), const_lambda_stub<TLambda>);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
// Set from non-capturing rvalue lambda convertible to function pointer.
|
||||
// Converts to a function pointer to avoid storing a dangling pointer
|
||||
// to a destroyed temporary.
|
||||
//*************************************************************************
|
||||
template <typename TLambda, etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_reference<TLambda>::value && etl::is_convertible<TLambda, TReturn(*)(TArgs...)>::value, int> = 0>
|
||||
void set(TLambda&& instance) ETL_NOEXCEPT
|
||||
{
|
||||
TReturn(*fp)(TArgs...) = static_cast<TReturn(*)(TArgs...)>(instance);
|
||||
assign(reinterpret_cast<void*>(fp), function_ptr_stub);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Set from instance method (Run time).
|
||||
//*************************************************************************
|
||||
@ -494,6 +532,19 @@ namespace etl
|
||||
return *this;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
// Create from non-capturing rvalue lambda convertible to function pointer.
|
||||
// Converts to a function pointer to avoid storing a dangling pointer
|
||||
// to a destroyed temporary.
|
||||
//*************************************************************************
|
||||
template <typename TLambda, etl::enable_if_t<etl::is_class<TLambda>::value && !etl::is_reference<TLambda>::value && etl::is_convertible<TLambda, TReturn(*)(TArgs...)>::value, int> = 0>
|
||||
delegate& operator =(TLambda&& instance) ETL_NOEXCEPT
|
||||
{
|
||||
TReturn(*fp)(TArgs...) = static_cast<TReturn(*)(TArgs...)>(instance);
|
||||
assign(reinterpret_cast<void*>(fp), function_ptr_stub);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Checks equality.
|
||||
//*************************************************************************
|
||||
@ -679,6 +730,16 @@ namespace etl
|
||||
return (Method)(etl::forward<TArgs>(args)...);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Stub call for a runtime function pointer stored in the object field.
|
||||
//*************************************************************************
|
||||
static TReturn function_ptr_stub(void* object, TArgs... args)
|
||||
{
|
||||
ETL_STATIC_ASSERT(sizeof(void*) >= sizeof(TReturn(*)(TArgs...)), "etl::delegate: function pointer too large to store in object field");
|
||||
TReturn(*fp)(TArgs...) = reinterpret_cast<TReturn(*)(TArgs...)>(object);
|
||||
return fp(etl::forward<TArgs>(args)...);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Stub call for a lambda or functor function.
|
||||
//*************************************************************************
|
||||
|
||||
@ -634,16 +634,55 @@ namespace
|
||||
#endif
|
||||
|
||||
//*************************************************************************
|
||||
TEST_FIXTURE(SetupFixture, test_lambda_int_create)
|
||||
TEST_FIXTURE(SetupFixture, test_construct_from_rvalue_non_capturing_lambda)
|
||||
{
|
||||
auto lambda = [](int i, int j) { function_called = FunctionCalled::Lambda_Called; parameter_correct = (i == VALUE1) && (j == VALUE2); };
|
||||
etl::delegate<int(int, int)> d([](int i, int j) { function_called = FunctionCalled::Lambda_Called; parameter_correct = (i == VALUE1) && (j == VALUE2); return i + j; });
|
||||
|
||||
etl::delegate<void(int, int)> d(lambda);
|
||||
|
||||
d(VALUE1, VALUE2);
|
||||
int result = d(VALUE1, VALUE2);
|
||||
|
||||
CHECK(function_called == FunctionCalled::Lambda_Called);
|
||||
CHECK(parameter_correct);
|
||||
CHECK_EQUAL(result, VALUE1 + VALUE2);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST_FIXTURE(SetupFixture, test_assign_from_rvalue_non_capturing_lambda)
|
||||
{
|
||||
etl::delegate<int(int, int)> d;
|
||||
|
||||
d = [](int i, int j) { function_called = FunctionCalled::Lambda_Called; parameter_correct = (i == VALUE1) && (j == VALUE2); return i + j + 2; };
|
||||
|
||||
int result = d(VALUE1, VALUE2);
|
||||
|
||||
CHECK(function_called == FunctionCalled::Lambda_Called);
|
||||
CHECK(parameter_correct);
|
||||
CHECK_EQUAL(result, VALUE1 + VALUE2 + 2);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST_FIXTURE(SetupFixture, test_create_from_rvalue_non_capturing_lambda)
|
||||
{
|
||||
auto d = etl::delegate<int(int, int)>::create([](int i, int j) { function_called = FunctionCalled::Lambda_Called; parameter_correct = (i == VALUE1) && (j == VALUE2); return i + j + 5; });
|
||||
|
||||
int result = d(VALUE1, VALUE2);
|
||||
|
||||
CHECK(function_called == FunctionCalled::Lambda_Called);
|
||||
CHECK(parameter_correct);
|
||||
CHECK_EQUAL(result, VALUE1 + VALUE2 + 5);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST_FIXTURE(SetupFixture, test_set_from_rvalue_non_capturing_lambda_returning_int)
|
||||
{
|
||||
etl::delegate<int(int, int)> d;
|
||||
|
||||
d.set([](int i, int j) { function_called = FunctionCalled::Lambda_Called; parameter_correct = (i == VALUE1) && (j == VALUE2); return i + j + 6; });
|
||||
|
||||
int result = d(VALUE1, VALUE2);
|
||||
|
||||
CHECK(function_called == FunctionCalled::Lambda_Called);
|
||||
CHECK(parameter_correct);
|
||||
CHECK_EQUAL(result, VALUE1 + VALUE2 + 6);
|
||||
}
|
||||
|
||||
#if ETL_USING_CPP17
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user