mirror of
https://github.com/ETLCPP/etl.git
synced 2026-04-30 19:09:10 +08:00
Add etl::inplace_function (#1251)
* Imported inplace_function and invoke functionality from original branch * Fixed spelling mistake * Update test/CMakeLists.txt Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update test/test_inplace_function.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Moved member type function_ptr to private section * Updated comments in inplace_function.h * Updated action workflows to be triggered on a pull-request based on development branch * Added suggested changes from PR reviews --------- Co-authored-by: John Wellbelove <john.wellbelove@etlcpp.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: John Wellbelove <john.wellbelove@etlcpp.co.uk>
This commit is contained in:
parent
09555434f6
commit
6d6ecc9fb5
2
.github/workflows/clang-c++11.yml
vendored
2
.github/workflows/clang-c++11.yml
vendored
@ -3,7 +3,7 @@ on:
|
||||
push:
|
||||
branches: [ master, development, pull-request/* ]
|
||||
pull_request:
|
||||
branches: [ master, pull-request/* ]
|
||||
branches: [ master, development, pull-request/* ]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
|
||||
2
.github/workflows/clang-c++14.yml
vendored
2
.github/workflows/clang-c++14.yml
vendored
@ -3,7 +3,7 @@ on:
|
||||
push:
|
||||
branches: [ master, development, pull-request/* ]
|
||||
pull_request:
|
||||
branches: [ master, pull-request/* ]
|
||||
branches: [ master, development, pull-request/* ]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
|
||||
2
.github/workflows/clang-c++17.yml
vendored
2
.github/workflows/clang-c++17.yml
vendored
@ -3,7 +3,7 @@ on:
|
||||
push:
|
||||
branches: [ master, development, pull-request/* ]
|
||||
pull_request:
|
||||
branches: [ master, pull-request/* ]
|
||||
branches: [ master, development, pull-request/* ]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
|
||||
2
.github/workflows/clang-c++20.yml
vendored
2
.github/workflows/clang-c++20.yml
vendored
@ -3,7 +3,7 @@ on:
|
||||
push:
|
||||
branches: [ master, development, pull-request/* ]
|
||||
pull_request:
|
||||
branches: [ master, pull-request/* ]
|
||||
branches: [ master, development, pull-request/* ]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
|
||||
3
.github/workflows/clang-c++23.yml
vendored
3
.github/workflows/clang-c++23.yml
vendored
@ -3,7 +3,8 @@ on:
|
||||
push:
|
||||
branches: [ master, development, pull-request/* ]
|
||||
pull_request:
|
||||
branches: [ master, pull-request/* ]
|
||||
branches: [ master, development, pull-request/* ]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
|
||||
|
||||
2
.github/workflows/clang-syntax-checks.yml
vendored
2
.github/workflows/clang-syntax-checks.yml
vendored
@ -3,7 +3,7 @@ on:
|
||||
push:
|
||||
branches: [ master, development, pull-request/* ]
|
||||
pull_request:
|
||||
branches: [ master, pull-request/* ]
|
||||
branches: [ master, development, pull-request/* ]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
|
||||
2
.github/workflows/gcc-c++11.yml
vendored
2
.github/workflows/gcc-c++11.yml
vendored
@ -3,7 +3,7 @@ on:
|
||||
push:
|
||||
branches: [ master, development, pull-request/* ]
|
||||
pull_request:
|
||||
branches: [ master, pull-request/* ]
|
||||
branches: [ master, development, pull-request/* ]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
|
||||
2
.github/workflows/gcc-c++14.yml
vendored
2
.github/workflows/gcc-c++14.yml
vendored
@ -3,7 +3,7 @@ on:
|
||||
push:
|
||||
branches: [ master, development, pull-request/* ]
|
||||
pull_request:
|
||||
branches: [ master, pull-request/* ]
|
||||
branches: [ master, development, pull-request/* ]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
|
||||
2
.github/workflows/gcc-c++17.yml
vendored
2
.github/workflows/gcc-c++17.yml
vendored
@ -3,7 +3,7 @@ on:
|
||||
push:
|
||||
branches: [ master, development, pull-request/* ]
|
||||
pull_request:
|
||||
branches: [ master, pull-request/* ]
|
||||
branches: [ master, development, pull-request/* ]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
|
||||
2
.github/workflows/gcc-c++20.yml
vendored
2
.github/workflows/gcc-c++20.yml
vendored
@ -3,7 +3,7 @@ on:
|
||||
push:
|
||||
branches: [ master, development, pull-request/* ]
|
||||
pull_request:
|
||||
branches: [ master, pull-request/* ]
|
||||
branches: [ master, development, pull-request/* ]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
|
||||
3
.github/workflows/gcc-c++23.yml
vendored
3
.github/workflows/gcc-c++23.yml
vendored
@ -3,7 +3,8 @@ on:
|
||||
push:
|
||||
branches: [ master, development, pull-request/* ]
|
||||
pull_request:
|
||||
branches: [ master, pull-request/* ]
|
||||
branches: [ master, development, pull-request/* ]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
|
||||
|
||||
2
.github/workflows/gcc-syntax-checks.yml
vendored
2
.github/workflows/gcc-syntax-checks.yml
vendored
@ -3,7 +3,7 @@ on:
|
||||
push:
|
||||
branches: [ master, development, pull-request/* ]
|
||||
pull_request:
|
||||
branches: [ master, pull-request/* ]
|
||||
branches: [ master, development, pull-request/* ]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
|
||||
2
.github/workflows/msvc.yml
vendored
2
.github/workflows/msvc.yml
vendored
@ -3,7 +3,7 @@ on:
|
||||
push:
|
||||
branches: [ master, development, pull-request/* ]
|
||||
pull_request:
|
||||
branches: [ master, pull-request/* ]
|
||||
branches: [ master, development, pull-request/* ]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
|
||||
@ -110,4 +110,5 @@ SOFTWARE.
|
||||
#define ETL_NOT_NULL_FILE_ID "77"
|
||||
#define ETL_SIGNAL_FILE_ID "78"
|
||||
#define ETL_FORMAT_FILE_ID "79"
|
||||
#define ETL_INPLACE_FUNCTION_FILE_ID "80"
|
||||
#endif
|
||||
|
||||
1529
include/etl/inplace_function.h
Normal file
1529
include/etl/inplace_function.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -36,7 +36,6 @@ SOFTWARE.
|
||||
#include "function_traits.h"
|
||||
#include "type_traits.h"
|
||||
#include "utility.h"
|
||||
#include "type_list.h"
|
||||
|
||||
#if ETL_USING_CPP11
|
||||
|
||||
@ -173,6 +172,37 @@ namespace etl
|
||||
static ETL_CONSTANT bool value = type::value;
|
||||
};
|
||||
|
||||
//*******************************************
|
||||
// Result type of a valid invocation.
|
||||
template <typename TFunction, typename... TArgs>
|
||||
struct invoke_result_impl
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int) -> decltype(etl::invoke(etl::declval<U>(), etl::declval<TArgs>()...));
|
||||
|
||||
template <typename>
|
||||
static void test(...);
|
||||
|
||||
using type = decltype(test<TFunction>(0));
|
||||
};
|
||||
|
||||
//*******************************************
|
||||
// Result type of a valid invocation.
|
||||
template <typename TFunction, typename... TArgs>
|
||||
struct invoke_result_impl<TFunction, etl::type_list<TArgs...>>
|
||||
{
|
||||
template <typename U>
|
||||
static auto test(int) -> decltype(etl::invoke(etl::declval<U>(), etl::declval<TArgs>()...));
|
||||
|
||||
template <typename>
|
||||
static void test(...);
|
||||
|
||||
using type = decltype(test<TFunction>(0));
|
||||
};
|
||||
|
||||
template <typename TFunction, typename... TArgs>
|
||||
using invoke_result_impl_t = typename invoke_result_impl<TFunction, TArgs...>::type;
|
||||
|
||||
//*******************************************
|
||||
// Map raw function type to pointer.
|
||||
template <typename TFunction>
|
||||
@ -195,7 +225,31 @@ namespace etl
|
||||
etl::void_t<decltype(etl::invoke(etl::declval<TFunction>(), etl::declval<TArgs>()...))>,
|
||||
TArgs...>
|
||||
{
|
||||
using type = decltype(etl::invoke(etl::declval<TFunction>(), etl::declval<TArgs>()...));
|
||||
private:
|
||||
|
||||
using FC = private_invoke::effective_callable_t<TFunction>;
|
||||
|
||||
public:
|
||||
|
||||
using type = etl::conditional_t<private_invoke::is_invocable_expr<FC, TArgs...>::value,
|
||||
private_invoke::invoke_result_impl_t<FC, TArgs...>,
|
||||
void>;
|
||||
};
|
||||
|
||||
//****************************************************************************
|
||||
/// invoke_result<TFunction, etl::type_list<TArgs...>>
|
||||
template <typename TFunction, typename... TArgs>
|
||||
struct invoke_result<TFunction, etl::type_list<TArgs...>>
|
||||
{
|
||||
private:
|
||||
|
||||
using FC = private_invoke::effective_callable_t<TFunction>;
|
||||
|
||||
public:
|
||||
|
||||
using type = etl::conditional_t<private_invoke::is_invocable_expr<FC, TArgs...>::value,
|
||||
private_invoke::invoke_result_impl_t<FC, TArgs...>,
|
||||
void>;
|
||||
};
|
||||
|
||||
//*******************************************
|
||||
|
||||
@ -201,6 +201,7 @@ add_executable(etl_tests
|
||||
test_index_of_type.cpp
|
||||
test_indirect_vector.cpp
|
||||
test_indirect_vector_external_buffer.cpp
|
||||
test_inplace_function.cpp
|
||||
test_instance_count.cpp
|
||||
test_integral_limits.cpp
|
||||
test_intrusive_forward_list.cpp
|
||||
@ -209,9 +210,10 @@ add_executable(etl_tests
|
||||
test_intrusive_queue.cpp
|
||||
test_intrusive_stack.cpp
|
||||
test_invert.cpp
|
||||
test_io_port.cpp
|
||||
test_iterator.cpp
|
||||
test_invoke.cpp
|
||||
test_io_port.cpp
|
||||
test_is_invocable.cpp
|
||||
test_iterator.cpp
|
||||
test_jenkins.cpp
|
||||
test_largest.cpp
|
||||
test_limiter.cpp
|
||||
|
||||
@ -217,6 +217,7 @@ target_sources(tests PRIVATE
|
||||
imemory_block_allocator.h.t.cpp
|
||||
indirect_vector.h.t.cpp
|
||||
initializer_list.h.t.cpp
|
||||
inplace_function.h.t.cpp
|
||||
instance_count.h.t.cpp
|
||||
integral_limits.h.t.cpp
|
||||
intrusive_forward_list.h.t.cpp
|
||||
@ -225,6 +226,7 @@ target_sources(tests PRIVATE
|
||||
intrusive_queue.h.t.cpp
|
||||
intrusive_stack.h.t.cpp
|
||||
invert.h.t.cpp
|
||||
invoke.h.t.cpp
|
||||
io_port.h.t.cpp
|
||||
ipool.h.t.cpp
|
||||
ireference_counted_message_pool.h.t.cpp
|
||||
|
||||
29
test/syntax_check/inplace_function.h.t.cpp
Normal file
29
test/syntax_check/inplace_function.h.t.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2025 John Wellbelove
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include <etl/inplace_function.h>
|
||||
29
test/syntax_check/invoke.h.t.cpp
Normal file
29
test/syntax_check/invoke.h.t.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
/******************************************************************************
|
||||
The MIT License(MIT)
|
||||
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
https://www.etlcpp.com
|
||||
|
||||
Copyright(c) 2025 John Wellbelove
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include <etl/invoke.h>
|
||||
1780
test/test_inplace_function.cpp
Normal file
1780
test/test_inplace_function.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -28,155 +28,457 @@ SOFTWARE.
|
||||
|
||||
#include "unit_test_framework.h"
|
||||
|
||||
#include <type_traits>
|
||||
#include <string>
|
||||
|
||||
#include "etl/type_traits.h"
|
||||
#include "etl/invoke.h"
|
||||
#include <etl/type_traits.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct TestClass
|
||||
//*************************************************************************
|
||||
// Callable subjects
|
||||
int free_add(int a, int b) { return a + b; }
|
||||
int free_noexcept(int v) noexcept { return v; }
|
||||
int free_throw(int v) { throw v; return v; }
|
||||
|
||||
// C-style variadic function
|
||||
int varfn(int first, ...) { return first; }
|
||||
|
||||
//*********************************************
|
||||
struct Base
|
||||
{
|
||||
int member_obj = 42;
|
||||
std::string member_str = "hello";
|
||||
int data;
|
||||
Base(int d = 10) : data(d) {}
|
||||
|
||||
int get_int()
|
||||
{
|
||||
return member_obj;
|
||||
}
|
||||
int add(int v) { return data + v; }
|
||||
int add_const(int v) const { return data + v + 1; }
|
||||
|
||||
int const_get_int() const
|
||||
{
|
||||
return member_obj + 10;
|
||||
}
|
||||
void set_int(int v)
|
||||
{
|
||||
member_obj = v;
|
||||
}
|
||||
static int static_func(int x)
|
||||
{
|
||||
return x * 2;
|
||||
}
|
||||
int ref_only(int v)& { return data + v + 2; }
|
||||
int rref_only(int v)&& { return data + v + 3; }
|
||||
|
||||
static int static_function(int v) { return v + 1; }
|
||||
int noexcept_member(int v) noexcept { return data + v; }
|
||||
};
|
||||
|
||||
int standalone_func(int a, int b)
|
||||
//*********************************************
|
||||
struct Derived : Base
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
Derived(int d = 20) : Base(d) {}
|
||||
};
|
||||
|
||||
//*********************************************
|
||||
struct VolatileBase
|
||||
{
|
||||
int x;
|
||||
VolatileBase(int v = 0) : x(v) {}
|
||||
int read() const volatile { return x; }
|
||||
};
|
||||
|
||||
//*********************************************
|
||||
struct Functor
|
||||
{
|
||||
int operator()(int x) const
|
||||
{
|
||||
return x * 5;
|
||||
}
|
||||
int x;
|
||||
explicit Functor(int x_) : x(x_) {}
|
||||
int operator()(int i) { return i + x; }
|
||||
};
|
||||
|
||||
SUITE(test_invoke)
|
||||
//*********************************************
|
||||
struct ConstFunctor
|
||||
{
|
||||
//*************************************************************************
|
||||
TEST(test_type_traits_functions)
|
||||
int x;
|
||||
explicit ConstFunctor(int x_) : x(x_) {}
|
||||
int operator()(int i) const { return i + x; }
|
||||
};
|
||||
|
||||
//*********************************************
|
||||
struct OverloadedFunctor
|
||||
{
|
||||
int operator()(int i)& { return i + 1; }
|
||||
int operator()(int i)&& { return i + 2; }
|
||||
};
|
||||
|
||||
//*********************************************
|
||||
struct MoveOnlyFunctor
|
||||
{
|
||||
MoveOnlyFunctor() = default;
|
||||
MoveOnlyFunctor(const MoveOnlyFunctor&) = delete;
|
||||
MoveOnlyFunctor(MoveOnlyFunctor&&) = default;
|
||||
int operator()(int i) { return i + 1; }
|
||||
};
|
||||
|
||||
//*********************************************
|
||||
struct NoThrowFunctor
|
||||
{
|
||||
int operator()(int i) const noexcept { return i + 2; }
|
||||
};
|
||||
|
||||
//*********************************************
|
||||
struct ThrowingFunctor
|
||||
{
|
||||
int operator()(int) { throw 42; }
|
||||
};
|
||||
|
||||
//*********************************************
|
||||
struct MemberObj
|
||||
{
|
||||
MemberObj(int v) : i(v)
|
||||
{
|
||||
CHECK_TRUE(etl::is_function<int(int)>::value);
|
||||
CHECK_TRUE(!etl::is_function<int>::value);
|
||||
CHECK_TRUE(!etl::is_function<int*>::value);
|
||||
CHECK_TRUE(!etl::is_function<int&>::value);
|
||||
CHECK_TRUE(!etl::is_function<int&&>::value);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_type_traits_member_pointers)
|
||||
{
|
||||
using MemObjPtr = int TestClass::*;
|
||||
using MemFnPtr = int (TestClass::*)();
|
||||
int i;
|
||||
};
|
||||
|
||||
CHECK_TRUE(etl::is_member_pointer<MemObjPtr>::value);
|
||||
CHECK_TRUE(etl::is_member_pointer<MemFnPtr>::value);
|
||||
CHECK_TRUE(!etl::is_member_pointer<int*>::value);
|
||||
//*********************************************
|
||||
template <typename T>
|
||||
struct IntegralOnly
|
||||
{
|
||||
template <typename U, typename = typename etl::enable_if<etl::is_integral<U>::value>::type>
|
||||
int operator()(U u) { return static_cast<int>(u) + 1; }
|
||||
|
||||
CHECK_TRUE(etl::is_member_object_pointer<MemObjPtr>::value);
|
||||
CHECK_TRUE(!etl::is_member_object_pointer<MemFnPtr>::value);
|
||||
template <typename U, typename = typename etl::enable_if<!etl::is_integral<U>::value>::type, typename = void>
|
||||
int operator()(U) = delete;
|
||||
};
|
||||
|
||||
CHECK_TRUE(!etl::is_member_function_pointer<MemObjPtr>::value);
|
||||
CHECK_TRUE(etl::is_member_function_pointer<MemFnPtr>::value);
|
||||
}
|
||||
//*********************************************
|
||||
// Non-capturing lambda (convertible to function pointer)
|
||||
static auto lambda_nc = [](int a, int b) { return a + b; };
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_invoke_callable)
|
||||
{
|
||||
CHECK_EQUAL(30, etl::invoke(standalone_func, 10, 20));
|
||||
#if ETL_USING_CPP14
|
||||
//*********************************************
|
||||
// Generic lambda (C++14+)
|
||||
static auto lambda_generic = [](auto x, auto y) { return x + y; };
|
||||
#endif
|
||||
|
||||
auto lambda = [](int x)
|
||||
{ return x * 3; };
|
||||
CHECK_EQUAL(15, etl::invoke(lambda, 5));
|
||||
//*********************************************
|
||||
// Overload set (not directly a single callable type for traits)
|
||||
int overload(int i) { return i + 10; }
|
||||
long overload(long l) { return l + 20; }
|
||||
|
||||
Functor f;
|
||||
CHECK_EQUAL(60, etl::invoke(f, 12));
|
||||
int takes_ptr(const int* p) { return *(p + 1); }
|
||||
|
||||
CHECK_EQUAL(8, etl::invoke(TestClass::static_func, 4));
|
||||
}
|
||||
//*********************************************
|
||||
struct Selective
|
||||
{
|
||||
template <typename T, etl::enable_if_t<etl::is_same<int, T>::value, int> = 0>
|
||||
int operator()(T) { return 1; }
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_invoke_mem_func_ptr)
|
||||
{
|
||||
TestClass obj;
|
||||
TestClass* ptr = &obj;
|
||||
const TestClass const_obj;
|
||||
template <typename T, etl::enable_if_t<etl::is_same<char, T>::value, int> = 0>
|
||||
char operator()(T) { return 2; }
|
||||
|
||||
CHECK_EQUAL(42, etl::invoke(&TestClass::get_int, obj));
|
||||
CHECK_EQUAL(42, etl::invoke(&TestClass::get_int, ptr));
|
||||
CHECK_EQUAL(52, etl::invoke(&TestClass::const_get_int, const_obj));
|
||||
template <typename T, etl::enable_if_t<!etl::is_integral<T>::value, int> = 0>
|
||||
int operator()(T) = delete;
|
||||
};
|
||||
}
|
||||
|
||||
etl::invoke(&TestClass::set_int, obj, 99);
|
||||
CHECK_EQUAL(99, obj.member_obj);
|
||||
//*************************************************************************
|
||||
// Unit tests for etl::is_invocable / etl::is_invocable_r
|
||||
//*************************************************************************
|
||||
SUITE(test_invoke)
|
||||
{
|
||||
//*************************************************************************
|
||||
TEST(test_invoke_result)
|
||||
{
|
||||
int capture_value = 5;
|
||||
auto lambda_cap = [capture_value](int a) { return a + capture_value; };
|
||||
|
||||
etl::invoke(&TestClass::set_int, ptr, 101);
|
||||
CHECK_EQUAL(101, ptr->member_obj);
|
||||
}
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(free_add), int, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(free_noexcept), int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(free_throw), int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(varfn), int>, int>::value));
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_invoke_mem_obj_ptr)
|
||||
{
|
||||
TestClass obj;
|
||||
TestClass* ptr = &obj;
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(&Base::add), Base, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(&Base::add_const), Base, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(&Base::ref_only), Base&, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(&Base::rref_only), Base, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(&Base::noexcept_member), Base, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(&Base::static_function), int>, int>::value));
|
||||
|
||||
CHECK_EQUAL(42, etl::invoke(&TestClass::member_obj, obj));
|
||||
CHECK_EQUAL(42, etl::invoke(&TestClass::member_obj, ptr));
|
||||
CHECK_EQUAL("hello", etl::invoke(&TestClass::member_str, obj));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(&Derived::add), Derived, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(&Derived::add_const), Derived, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(&Derived::ref_only), Derived&, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(&Derived::rref_only), Derived, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(&Derived::noexcept_member), Derived, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(&Derived::static_function), int>, int>::value));
|
||||
|
||||
etl::invoke(&TestClass::member_obj, obj) = 1000;
|
||||
CHECK_EQUAL(1000, obj.member_obj);
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(&VolatileBase::read), VolatileBase>, int>::value));
|
||||
|
||||
etl::invoke(&TestClass::member_obj, ptr) = 2000;
|
||||
CHECK_EQUAL(2000, ptr->member_obj);
|
||||
}
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<Functor, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<ConstFunctor, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<OverloadedFunctor&, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<OverloadedFunctor&&, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<MoveOnlyFunctor, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<NoThrowFunctor, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<ThrowingFunctor, int>, int>::value));
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_invoke_result_t)
|
||||
{
|
||||
using MemFnPtr = decltype(&TestClass::get_int);
|
||||
using ConstMemFnPtr = decltype(&TestClass::const_get_int);
|
||||
using MemObjPtr_int = decltype(&TestClass::member_obj);
|
||||
using FnPtr = int (*)(int, int);
|
||||
|
||||
auto val = etl::is_same<etl::invoke_result_t<FnPtr, int, int>, int>::value;
|
||||
CHECK_TRUE(val);
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(&MemberObj::i), MemberObj&>, int&>::value));
|
||||
|
||||
val = etl::is_same<etl::invoke_result_t<MemFnPtr, TestClass&>, int>::value;
|
||||
CHECK_TRUE(val);
|
||||
|
||||
val = etl::is_same<etl::invoke_result_t<MemFnPtr, TestClass*>, int>::value;
|
||||
CHECK_TRUE(val);
|
||||
|
||||
val = etl::is_same<etl::invoke_result_t<ConstMemFnPtr, const TestClass&>, int>::value;
|
||||
CHECK_TRUE(val);
|
||||
|
||||
val = etl::is_same<etl::invoke_result_t<MemObjPtr_int, TestClass&>, int&>::value;
|
||||
CHECK_TRUE(val);
|
||||
|
||||
val = etl::is_same<etl::invoke_result_t<MemObjPtr_int, const TestClass&>, const int&>::value;
|
||||
CHECK_TRUE(val);
|
||||
|
||||
val = etl::is_same<etl::invoke_result_t<MemObjPtr_int, TestClass*>, int&>::value;
|
||||
CHECK_TRUE(val);
|
||||
}
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<IntegralOnly<int>, int>, int>::value));
|
||||
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(lambda_nc), int, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(lambda_cap), int>, int>::value));
|
||||
#if ETL_USING_CPP14
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(lambda_generic), int, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(lambda_generic), long, short>, long>::value));
|
||||
#endif
|
||||
|
||||
int (*ov_int)(int) = &overload;
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(ov_int), int>, int>::value));
|
||||
|
||||
long (*ov_long)(long) = &overload;
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(ov_long), long>, long>::value));
|
||||
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<Selective, int>, int>::value));
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<Selective, char>, char>::value));
|
||||
|
||||
CHECK_TRUE((etl::is_same<etl::invoke_result_t<decltype(takes_ptr), const int* >, int>::value));
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_free_function)
|
||||
{
|
||||
CHECK_EQUAL(3, etl::invoke(free_add, 1, 2));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_free_function_pointer_variable)
|
||||
{
|
||||
int (*fp)(int, int) = &free_add;
|
||||
|
||||
CHECK_EQUAL(3, etl::invoke(fp, 1, 2));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_function_pointer_const_qualification)
|
||||
{
|
||||
int (*const cfp)(int, int) = &free_add;
|
||||
|
||||
CHECK_EQUAL(3, etl::invoke(cfp, 1, 2));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_free_function_noexcept)
|
||||
{
|
||||
CHECK_EQUAL(1, etl::invoke(free_noexcept, 1));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_free_function_throw)
|
||||
{
|
||||
CHECK_THROW(etl::invoke(free_throw, 1), int);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_static_member_function)
|
||||
{
|
||||
CHECK_EQUAL(2, etl::invoke(&Base::static_function, 1));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_member_function)
|
||||
{
|
||||
Base base(10);
|
||||
const Base const_base(20);
|
||||
|
||||
Base* p_base = &base;
|
||||
const Base* p_const_base = &const_base;
|
||||
|
||||
CHECK_EQUAL(11, etl::invoke(&Base::add, base, 1));
|
||||
CHECK_EQUAL(12, etl::invoke(&Base::add, p_base, 2));
|
||||
CHECK_EQUAL(14, etl::invoke(&Base::add_const, base, 3));
|
||||
CHECK_EQUAL(15, etl::invoke(&Base::add_const, p_base, 4));
|
||||
CHECK_EQUAL(26, etl::invoke(&Base::add_const, const_base, 5));
|
||||
CHECK_EQUAL(27, etl::invoke(&Base::add_const, p_const_base, 6));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_member_function_noexcept)
|
||||
{
|
||||
Base base(10);
|
||||
|
||||
CHECK_EQUAL(11, etl::invoke(&Base::noexcept_member, base, 1));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_member_functions_ref_qualification)
|
||||
{
|
||||
Base base(10);
|
||||
Base& base_ref = base;
|
||||
|
||||
Base&& base_rref = Base(10);
|
||||
|
||||
CHECK_EQUAL(13, etl::invoke(&Base::ref_only, base_ref, 1));
|
||||
CHECK_EQUAL(15, etl::invoke(&Base::rref_only, std::move(base_rref), 2));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_inheritance_member_function)
|
||||
{
|
||||
Derived derived(10);
|
||||
Derived* p_derived = &derived;
|
||||
|
||||
CHECK_EQUAL(11, etl::invoke(&Base::add, derived, 1));
|
||||
CHECK_EQUAL(12, etl::invoke(&Base::add, p_derived, 2));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_member_function_volatile)
|
||||
{
|
||||
VolatileBase volatile_base(10);
|
||||
|
||||
CHECK_EQUAL(10, etl::invoke(&VolatileBase::read, volatile_base));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_member_object_pointer)
|
||||
{
|
||||
MemberObj obj(10);
|
||||
|
||||
CHECK_EQUAL(10, etl::invoke(&MemberObj::i, obj));
|
||||
CHECK_EQUAL(20, etl::invoke(&MemberObj::i, obj) = 20);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_functor_non_const)
|
||||
{
|
||||
Functor functor(10);
|
||||
|
||||
CHECK_EQUAL(12, etl::invoke(functor, 2));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_functor_const)
|
||||
{
|
||||
const ConstFunctor functor(10);
|
||||
|
||||
CHECK_EQUAL(12, etl::invoke(functor, 2));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_move_only_functor)
|
||||
{
|
||||
MoveOnlyFunctor functor;
|
||||
|
||||
CHECK_EQUAL(11, etl::invoke(etl::move(functor), 10));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_overloaded_functor_ref_qualifier)
|
||||
{
|
||||
OverloadedFunctor functor;
|
||||
OverloadedFunctor& functor_ref = functor;
|
||||
OverloadedFunctor&& functor_rref = OverloadedFunctor();
|
||||
|
||||
CHECK_EQUAL(11, etl::invoke(functor_ref, 10));
|
||||
CHECK_EQUAL(12, etl::invoke(etl::move(functor_rref), 10));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_nothrow_and_throwing_functors)
|
||||
{
|
||||
NoThrowFunctor nothrow_functor;
|
||||
ThrowingFunctor throwing_functor;
|
||||
|
||||
CHECK_EQUAL(12, etl::invoke(nothrow_functor, 10));
|
||||
CHECK_THROW(etl::invoke(throwing_functor, 10), int);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_lambda_non_capturing)
|
||||
{
|
||||
CHECK_EQUAL(3, etl::invoke(lambda_nc, 1, 2));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_lambda_capturing)
|
||||
{
|
||||
int capture_value = 5;
|
||||
auto lambda_cap = [capture_value](int a) { return a + capture_value; };
|
||||
|
||||
CHECK_EQUAL(6, etl::invoke(lambda_cap, 1));
|
||||
}
|
||||
|
||||
#if ETL_USING_CPP14
|
||||
//*************************************************************************
|
||||
TEST(test_lambda_generic)
|
||||
{
|
||||
CHECK_EQUAL(3, etl::invoke(lambda_generic, 1, 2));
|
||||
CHECK_EQUAL(3L, etl::invoke(lambda_generic, 1L, 2L));
|
||||
CHECK_CLOSE(3.5, etl::invoke(lambda_generic, 1.5, 2.0), 0.001);
|
||||
}
|
||||
#endif
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_template_functor_integral_only)
|
||||
{
|
||||
CHECK_EQUAL(2, etl::invoke(IntegralOnly<int>(), 1));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_additional_user_defined_conversion)
|
||||
{
|
||||
struct Converter { operator int() const { return 11; } };
|
||||
|
||||
CHECK_EQUAL(22, etl::invoke(free_add, Converter(), 11)); // Converter -> int
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_overload_set)
|
||||
{
|
||||
// Selecting explicit overload
|
||||
int (*ov_i)(int) = &overload;
|
||||
long (*ov_l)(long) = &overload;
|
||||
|
||||
CHECK_EQUAL(11, etl::invoke(ov_i, 1));
|
||||
CHECK_EQUAL(21L, etl::invoke(ov_l, 1L));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_deleted_overload)
|
||||
{
|
||||
struct DeletedOverload
|
||||
{
|
||||
int operator()(double d) { return static_cast<int>(2 * d); }
|
||||
int operator()(int) = delete;
|
||||
};
|
||||
|
||||
CHECK_CLOSE(6, etl::invoke(DeletedOverload(), 3.14), 0.001);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_variadic_free_function)
|
||||
{
|
||||
CHECK_EQUAL(1, etl::invoke(varfn, 1));
|
||||
CHECK_EQUAL(2, etl::invoke(varfn, 2, 3.14, "test"));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_array_decay_argument)
|
||||
{
|
||||
int arr[] = {1, 2, 3};
|
||||
|
||||
CHECK_EQUAL(2, etl::invoke(takes_ptr, arr));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_template_functor_multiple_enable_if)
|
||||
{
|
||||
CHECK_EQUAL(1, etl::invoke(Selective(), int(0)));
|
||||
CHECK_EQUAL(2, etl::invoke(Selective(), char(0)));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_rvalue_ref_member_on_temporary)
|
||||
{
|
||||
struct RR
|
||||
{
|
||||
int f() && { return 1; }
|
||||
int g() & { return 2; }
|
||||
};
|
||||
|
||||
RR rr;
|
||||
|
||||
CHECK_EQUAL(1, etl::invoke(&RR::f, etl::move(rr)));
|
||||
CHECK_EQUAL(2, etl::invoke(&RR::g, rr));
|
||||
}
|
||||
}
|
||||
|
||||
1011
test/test_is_invocable.cpp
Normal file
1011
test/test_is_invocable.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -3544,6 +3544,7 @@
|
||||
<ClInclude Include="..\..\include\etl\function_traits.h" />
|
||||
<ClInclude Include="..\..\include\etl\gcd.h" />
|
||||
<ClInclude Include="..\..\include\etl\index_of_type.h" />
|
||||
<ClInclude Include="..\..\include\etl\inplace_function.h" />
|
||||
<ClInclude Include="..\..\include\etl\invoke.h" />
|
||||
<ClInclude Include="..\..\include\etl\lcm.h" />
|
||||
<ClInclude Include="..\..\include\etl\math.h" />
|
||||
@ -10347,8 +10348,10 @@
|
||||
<ClCompile Include="..\test_hfsm_recurse_to_inner_state_on_start.cpp" />
|
||||
<ClCompile Include="..\test_hfsm_transition_on_enter.cpp" />
|
||||
<ClCompile Include="..\test_index_of_type.cpp" />
|
||||
<ClCompile Include="..\test_inplace_function.cpp" />
|
||||
<ClCompile Include="..\test_intrusive_links.cpp" />
|
||||
<ClCompile Include="..\test_invoke.cpp" />
|
||||
<ClCompile Include="..\test_is_invocable.cpp" />
|
||||
<ClCompile Include="..\test_macros.cpp" />
|
||||
<ClCompile Include="..\test_math.cpp" />
|
||||
<ClCompile Include="..\test_math_functions.cpp" />
|
||||
|
||||
@ -1534,7 +1534,10 @@
|
||||
<Filter>UnitTest++\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\etl\invoke.h">
|
||||
<Filter>UnitTest++\Header Files</Filter>
|
||||
<Filter>ETL\Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\etl\inplace_function.h">
|
||||
<Filter>ETL\Utilities</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -3761,6 +3764,12 @@
|
||||
<ClCompile Include="..\test_invoke.cpp">
|
||||
<Filter>Tests\Callbacks & Delegates</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\test_is_invocable.cpp">
|
||||
<Filter>Tests\Callbacks & Delegates</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\test_inplace_function.cpp">
|
||||
<Filter>Tests\Callbacks & Delegates</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\library.properties">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user