basedOpinionated utility library |
git clone git://git.dimitrijedobrota.com/based.git |
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING |
commit | 4d76aec6d751582155fc6ca5802dd8c7932cc8f4 |
parent | 4d55232d42d00afb41a2b65d88e291bddc2cc1ea |
author | Dimitrije Dobrota < mail@dimitrijedobrota.com > |
date | Tue, 29 Apr 2025 13:07:32 +0200 |
function test, improved deduction guides
M | example/template.cpp | | | + - |
M | include/based/template.hpp | | | +++++++++++++++++++ -------- |
M | test/CMakeLists.txt | | | + |
A | test/source/function_test.cpp | | | ++++++++++++++++++++++++++++++++++++++++++++++ |
M | test/source/signature_test.cpp | | | +++++++++ ---- |
5 files changed, 76 insertions(+), 13 deletions(-)
diff --git a/ example/template.cpp b/ example/template.cpp
@@ -25,7 +25,7 @@
int main()
}
{
const based::Function func = [](int val)
const based::function func = [](int val)
{
return val + 1;
};
diff --git a/ include/based/template.hpp b/ include/based/template.hpp
@@ -298,14 +298,14 @@
template<
typename Signature,
std::size_t size = sizeof(void*),
std::size_t alignment = alignof(void*)>
class Function;
class function;
template<
std::size_t size,
std::size_t alignment,
typename Res,
typename... Args>
class Function<Res(Args...), size, alignment>
class function<Res(Args...), size, alignment>
{
buffer<size, alignment> m_space;
@@ -323,24 +323,24 @@
class Function<Res(Args...), size, alignment>
static Res executor(Args... args, void* func)
{
return std::invoke(
*static_cast<Function*>(func)->m_space.template as<Callable>(),
*static_cast<function*>(func)->m_space.template as<Callable>(),
std::forward<Args>(args)...
);
}
public:
Function() = default;
function() = default;
template<typename CallableArg, typename Callable = std::decay_t<CallableArg>>
requires(requires {
!std::same_as<Function, Callable>;
!std::same_as<function, Callable>;
sizeof(Callable) <= size;
alignof(Callable) <= alignment;
std::is_trivially_destructible_v<Callable>;
std::is_trivially_copyable_v<Callable>;
})
Function(CallableArg&& callable) // NOLINT explicit
function(CallableArg&& callable) // NOLINT explicit
: m_space(
std::in_place_type<Callable>, std::forward<CallableArg>(callable)
)
@@ -353,13 +353,24 @@
public:
{
return this->m_executor(
std::forward<CallArgs>(callargs)...,
const_cast<Function*>(this) // NOLINT const_cast
const_cast<function*>(this) // NOLINT const_cast
);
}
};
// operator()
template<typename T>
Function(T) -> Function<typename signature<decltype(&T::operator())>::sig_type>;
function(T) -> function<typename signature<decltype(&T::operator())>::sig_type>;
// free function
template<typename T>
function(T) -> function<typename signature<std::remove_pointer_t<T>>::sig_type>;
/*
// member procedure
template<typename T>
function(T) -> function<typename signature<std::decay_t<T>>::sig_type>;
*/
template<Procedure Func, bool on_success = false, bool on_failure = false>
class scopeguard
diff --git a/ test/CMakeLists.txt b/ test/CMakeLists.txt
@@ -67,6 +67,7 @@
add_test(string_literal_test)
add_test(signature_test)
add_test(buffer_test)
add_test(function_test)
# ---- End-of-file commands ----
diff --git a/ test/source/function_test.cpp b/ test/source/function_test.cpp
@@ -0,0 +1,46 @@
#include <catch2/catch_test_macros.hpp>
#include "based/template.hpp"
namespace
{
int identity(int a)
{
return a;
}
} // namespace
template class based::function<decltype(identity)>;
TEST_CASE("empty", "[template/function]")
{
const based::function<void()> func;
try {
func();
REQUIRE(false);
} catch (const std::bad_function_call& err) {
REQUIRE(true);
} catch (...) {
REQUIRE(false);
}
}
TEST_CASE("free function", "[template/function]")
{
const based::function func = identity;
REQUIRE(func(3) == 3);
}
TEST_CASE("lambda function", "[template/function]")
{
const based::function func = [](int a)
{
return a;
};
REQUIRE(func(3) == 3);
}
diff --git a/ test/source/signature_test.cpp b/ test/source/signature_test.cpp
@@ -4,17 +4,20 @@
#include "based/template.hpp"
// NOLINTBEGIN cognitive-complexity
namespace
{
int free_func(const double& a, int&& b) noexcept(false) // NOLINT
int free_func(const double& a, int&& b) noexcept(false) // NOLINT needed
{
return static_cast<int>(a + std::move(b)); // NOLINT
return static_cast<int>(a + std::move(b)); // NOLINT move
}
int free_func_noexcept(const double& a, int&& b) noexcept(true) // NOLINT
int free_func_noexcept(const double& a, int&& b) noexcept(true
) // NOLINT needed
{
return static_cast<int>(a + std::move(b)); // NOLINT
return static_cast<int>(a + std::move(b)); // NOLINT move
}
} // namespace
@@ -468,3 +471,5 @@
TEST_CASE("const volatile noexcept rvalref", "[template/signature]")
STATIC_REQUIRE(std::same_as<std::true_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::noexcept_val>);
}
// NOLINTEND cognitive-complexity