based

Opinionated utility library
git clone git://git.dimitrijedobrota.com/based.git
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING

commit 2272f546a59ff1312ab61aecfb0e2388b27d2fc9
parent 430b25f434f63656e1b5353e78c4648ab5335ed3
author Dimitrije Dobrota < mail@dimitrijedobrota.com >
date Tue, 29 Apr 2025 11:44:02 +0200

Test all function signature combinations

Diffstat:
M include/based/template.hpp | ++++ --
M test/CMakeLists.txt | +++
A test/source/signature_test.cpp | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

3 files changed, 477 insertions(+), 2 deletions(-)


diff --git a/ include/based/template.hpp b/ include/based/template.hpp

@@ -18,12 +18,14 @@ namespace based

template<typename>
struct signature;

template<typename Ret, typename... Args>
struct signature<Ret(Args...)>
template<typename Ret, bool ne, typename... Args>
struct signature<Ret(Args...) noexcept(ne)>
{
using sig_type = Ret(Args...);
using arg_type = std::tuple<Args...>;
using ret_type = Ret;

using noexcept_val = std::integral_constant<bool, ne>;
};

template<typename Ret, typename Obj, bool ne, typename... Args>

diff --git a/ test/CMakeLists.txt b/ test/CMakeLists.txt

@@ -61,6 +61,9 @@ add_test(list_test)

# ---- String ----
add_test(string_literal_test)

# ---- Template ----
add_test(signature_test)

# ---- End-of-file commands ----

add_folders(Test)

diff --git a/ test/source/signature_test.cpp b/ test/source/signature_test.cpp

@@ -0,0 +1,470 @@

#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE

#include <catch2/catch_test_macros.hpp>

#include "based/template.hpp"

namespace
{

int free_func(const double& a, int&& b) noexcept(false) // NOLINT
{
return static_cast<int>(a + std::move(b)); // NOLINT
}

int free_func_noexcept(const double& a, int&& b) noexcept(true) // NOLINT
{
return static_cast<int>(a + std::move(b)); // NOLINT
}

} // namespace

TEST_CASE("free function", "[template/signature]")
{
using sig = based::signature<decltype(free_func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::noexcept_val>);
}

TEST_CASE("free function noexcept", "[template/signature]")
{
using sig = based::signature<decltype(free_func_noexcept)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::noexcept_val>);
}

TEST_CASE("empty", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::noexcept_val>);
}

TEST_CASE("const", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) const noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::noexcept_val>);
}

TEST_CASE("volatile", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::noexcept_val>);
}

TEST_CASE("const volatile", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::noexcept_val>);
}

TEST_CASE("noexcept", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::noexcept_val>);
}

TEST_CASE("const noexcept", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) const noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::noexcept_val>);
}

TEST_CASE("volatile noexcept", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::noexcept_val>);
}

TEST_CASE("const volatile noexcept", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::noexcept_val>);
}

TEST_CASE("lvalref", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) & noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::noexcept_val>);
}

TEST_CASE("const lvalref", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) const& noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::noexcept_val>);
}

TEST_CASE("volatile lvalref", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile& noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::noexcept_val>);
}

TEST_CASE("const volatile lvalref", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile& noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::noexcept_val>);
}

TEST_CASE("noexcept lvalref", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) & noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::noexcept_val>);
}

TEST_CASE("const noexcept lvalref", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) const& noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::noexcept_val>);
}

TEST_CASE("volatile noexcept lvalref", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile& noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::noexcept_val>);
}

TEST_CASE("const volatile noexcept lvalref", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile& noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::noexcept_val>);
}

TEST_CASE("rvalref", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) && noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::noexcept_val>);
}

TEST_CASE("const rvalref", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) const&& noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::noexcept_val>);
}

TEST_CASE("volatile rvalref", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile&& noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::noexcept_val>);
}

TEST_CASE("const volatile rvalref", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile&& noexcept(false);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::noexcept_val>);
}

TEST_CASE("noexcept rvalref", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) && noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::noexcept_val>);
}

TEST_CASE("const noexcept rvalref", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) const&& noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::noexcept_val>);
}

TEST_CASE("volatile noexcept rvalref", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) volatile&& noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::noexcept_val>);
}

TEST_CASE("const volatile noexcept rvalref", "[template/signature]")
{
struct test
{
int func(const double& a, int&& b) const volatile&& noexcept(true);
};

using sig = based::signature<decltype(&test::func)>;
STATIC_REQUIRE(std::same_as<int(const double&, int&&), sig::sig_type>);
STATIC_REQUIRE(std::same_as<std::tuple<const double&, int&&>, sig::arg_type>);
STATIC_REQUIRE(std::same_as<int, sig::ret_type>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::const_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::volatile_val>);
STATIC_REQUIRE(std::same_as<std::false_type, sig::lvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::rvalref_val>);
STATIC_REQUIRE(std::same_as<std::true_type, sig::noexcept_val>);
}