From 187d3dacf9de7b3d59133577f0d5fd672c865386 Mon Sep 17 00:00:00 2001 From: Liss Heidrich <31625940+liss-h@users.noreply.github.com> Date: Thu, 30 Apr 2026 11:35:00 +0200 Subject: [PATCH 1/7] disable comp functions if they don't work --- include/dice/template-library/variant2.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/dice/template-library/variant2.hpp b/include/dice/template-library/variant2.hpp index 4cadd35..fa0bd26 100644 --- a/include/dice/template-library/variant2.hpp +++ b/include/dice/template-library/variant2.hpp @@ -720,7 +720,7 @@ namespace dice::template_library { rhs = std::move(tmp); } - constexpr bool operator==(variant2 const &other) const noexcept { + constexpr bool operator==(variant2 const &other) const noexcept requires (std::equality_comparable && std::equality_comparable) { if (discriminant_ != other.discriminant_) { return false; } @@ -742,7 +742,7 @@ namespace dice::template_library { } } - constexpr auto operator<=>(variant2 const &other) const noexcept { + constexpr auto operator<=>(variant2 const &other) const noexcept requires (std::three_way_comparable && std::three_way_comparable) { using ret_type = std::common_comparison_category_t, std::compare_three_way_result_t>; if (discriminant_ != other.discriminant_) { From 1c8c4c7303cdc4fc4b2392f2c757577c5535a493 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 30 Apr 2026 16:13:39 +0200 Subject: [PATCH 2/7] Add `std::formatter` specialization and tests for `variant2` --- include/dice/template-library/variant2.hpp | 26 ++++++++++++++++++++++ tests/tests_variant2.cpp | 17 ++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/include/dice/template-library/variant2.hpp b/include/dice/template-library/variant2.hpp index fa0bd26..c387ee5 100644 --- a/include/dice/template-library/variant2.hpp +++ b/include/dice/template-library/variant2.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -903,4 +904,29 @@ namespace dice::template_library { } // namespace dice::template_library +namespace std { + template + requires (std::formattable || std::formattable) + struct formatter<::dice::template_library::variant2, CharT> { + template + constexpr auto parse(Ctx &parse_ctx) { + return parse_ctx.begin(); + } + + template + auto format(::dice::template_library::variant2 const &var, Ctx &format_ctx) const { + if (var.valueless_by_exception()) { + return std::format_to(format_ctx.out(), "var2"); + } + return ::dice::template_library::visit([&format_ctx](X const &value) { + if constexpr (std::formattable) { + return std::format_to(format_ctx.out(), "var2<{}>", value); + } else { + return std::format_to(format_ctx.out(), "var2"); + } + }, var); + } + }; +} // namespace std + #endif // DICE_TEMPLATELIBRARY_VARIANT2_HPP diff --git a/tests/tests_variant2.cpp b/tests/tests_variant2.cpp index c4476bc..650e674 100644 --- a/tests/tests_variant2.cpp +++ b/tests/tests_variant2.cpp @@ -289,4 +289,21 @@ TEST_SUITE("variant2") { static_assert(!std::is_trivially_destructible_v); static_assert(!std::is_trivially_copyable_v); } + + TEST_CASE("formatting") { + struct non_formattable { + }; + + static_assert(!std::formattable, char>); + + CHECK(std::format("{}", variant2{42}) == "var2<42>"); + CHECK(std::format("{}", variant2{1.5}) == "var2<1.5>"); + CHECK(std::format("{}", variant2{5}) == "var2<5>"); + CHECK(std::format("{}", variant2{non_formattable{}}) == "var2"); + + variant2 valueless{}; + try { valueless = make_valueless{std::nothrow}; } catch (...) { + } + CHECK(std::format("{}", valueless) == "var2"); + } } From e8851d64db8769e6381311e1ae11ba8b1bd8fbc7 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 30 Apr 2026 16:41:49 +0200 Subject: [PATCH 3/7] fix --- include/dice/template-library/variant2.hpp | 3 +-- tests/tests_variant2.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/dice/template-library/variant2.hpp b/include/dice/template-library/variant2.hpp index c387ee5..03c152b 100644 --- a/include/dice/template-library/variant2.hpp +++ b/include/dice/template-library/variant2.hpp @@ -906,7 +906,6 @@ namespace dice::template_library { namespace std { template - requires (std::formattable || std::formattable) struct formatter<::dice::template_library::variant2, CharT> { template constexpr auto parse(Ctx &parse_ctx) { @@ -914,7 +913,7 @@ namespace std { } template - auto format(::dice::template_library::variant2 const &var, Ctx &format_ctx) const { + constexpr auto format(::dice::template_library::variant2 const &var, Ctx &format_ctx) const { if (var.valueless_by_exception()) { return std::format_to(format_ctx.out(), "var2"); } diff --git a/tests/tests_variant2.cpp b/tests/tests_variant2.cpp index 650e674..758ad52 100644 --- a/tests/tests_variant2.cpp +++ b/tests/tests_variant2.cpp @@ -294,7 +294,7 @@ TEST_SUITE("variant2") { struct non_formattable { }; - static_assert(!std::formattable, char>); + static_assert(std::formattable, char>); CHECK(std::format("{}", variant2{42}) == "var2<42>"); CHECK(std::format("{}", variant2{1.5}) == "var2<1.5>"); From 897c794f8b699d80fca653c58326dbbee661372f Mon Sep 17 00:00:00 2001 From: Liss Heidrich <31625940+liss-h@users.noreply.github.com> Date: Mon, 4 May 2026 14:20:40 +0200 Subject: [PATCH 4/7] fix variant formatting --- include/dice/template-library/variant2.hpp | 37 ++++------ tests/tests_variant2.cpp | 86 ++++++++++++---------- 2 files changed, 63 insertions(+), 60 deletions(-) diff --git a/include/dice/template-library/variant2.hpp b/include/dice/template-library/variant2.hpp index 03c152b..9f672f8 100644 --- a/include/dice/template-library/variant2.hpp +++ b/include/dice/template-library/variant2.hpp @@ -904,28 +904,23 @@ namespace dice::template_library { } // namespace dice::template_library -namespace std { - template - struct formatter<::dice::template_library::variant2, CharT> { - template - constexpr auto parse(Ctx &parse_ctx) { - return parse_ctx.begin(); - } +template requires (std::formattable && std::formattable) +struct std::formatter<::dice::template_library::variant2> { + template + constexpr auto parse(Ctx &ctx) { + return ctx.begin(); + } - template - constexpr auto format(::dice::template_library::variant2 const &var, Ctx &format_ctx) const { - if (var.valueless_by_exception()) { - return std::format_to(format_ctx.out(), "var2"); - } - return ::dice::template_library::visit([&format_ctx](X const &value) { - if constexpr (std::formattable) { - return std::format_to(format_ctx.out(), "var2<{}>", value); - } else { - return std::format_to(format_ctx.out(), "var2"); - } - }, var); + template + auto format(::dice::template_library::variant2 const &var, Ctx &ctx) const { + // formatting the same way libfmt does + if (var.valueless_by_exception()) { + return std::format_to(ctx.out(), "variant(valueless by exception)"); } - }; -} // namespace std + return ::dice::template_library::visit([&ctx](auto const &value) { + return std::format_to(ctx.out(), "variant({})", value); + }, var); + } +}; #endif // DICE_TEMPLATELIBRARY_VARIANT2_HPP diff --git a/tests/tests_variant2.cpp b/tests/tests_variant2.cpp index 758ad52..1e0401a 100644 --- a/tests/tests_variant2.cpp +++ b/tests/tests_variant2.cpp @@ -7,6 +7,47 @@ using namespace std::string_literals; +struct make_valueless { + make_valueless() { + throw std::runtime_error{"aaa"}; + } + + explicit make_valueless(std::nothrow_t) noexcept {} + + make_valueless(make_valueless const &) { + throw std::runtime_error{"aaa"}; + } + + make_valueless(make_valueless &&) { + throw std::runtime_error{"aaa"}; + } + + make_valueless &operator=(make_valueless const &) { + throw std::runtime_error{"aaa"}; + } + + make_valueless &operator=(make_valueless &&) { + throw std::runtime_error{"aaa"}; + } + + ~make_valueless() noexcept = default; + + auto operator<=>(make_valueless const &) const noexcept = default; +}; + +template<> +struct std::formatter { + template + constexpr auto parse(Ctx &parse_ctx) { + return parse_ctx.begin(); + } + + template + auto format(make_valueless, Ctx &format_ctx) const { + return std::format_to(format_ctx.out(), "make_valueluess"); + } +}; + TEST_SUITE("variant2") { using namespace dice::template_library; @@ -29,34 +70,6 @@ TEST_SUITE("variant2") { && std::is_const_v> == std::is_const_v>; - struct make_valueless { - make_valueless() { - throw std::runtime_error{"aaa"}; - } - - explicit make_valueless(std::nothrow_t) noexcept {} - - make_valueless(make_valueless const &) { - throw std::runtime_error{"aaa"}; - } - - make_valueless(make_valueless &&) { - throw std::runtime_error{"aaa"}; - } - - make_valueless &operator=(make_valueless const &) { - throw std::runtime_error{"aaa"}; - } - - make_valueless &operator=(make_valueless &&) { - throw std::runtime_error{"aaa"}; - } - - ~make_valueless() noexcept = default; - - auto operator<=>(make_valueless const &) const noexcept = default; - }; - template void check_acessors(Variant &&x, T const &expected_val) { static constexpr size_t index = variant_index>::value; @@ -291,19 +304,14 @@ TEST_SUITE("variant2") { } TEST_CASE("formatting") { - struct non_formattable { - }; - - static_assert(std::formattable, char>); - - CHECK(std::format("{}", variant2{42}) == "var2<42>"); - CHECK(std::format("{}", variant2{1.5}) == "var2<1.5>"); - CHECK(std::format("{}", variant2{5}) == "var2<5>"); - CHECK(std::format("{}", variant2{non_formattable{}}) == "var2"); + CHECK(std::format("{}", variant2{42}) == "variant(42)"); + CHECK(std::format("{}", variant2{1.5}) == "variant(1.5)"); variant2 valueless{}; - try { valueless = make_valueless{std::nothrow}; } catch (...) { + try { + valueless = make_valueless{std::nothrow}; + } catch (...) { } - CHECK(std::format("{}", valueless) == "var2"); + CHECK(std::format("{}", valueless) == "variant(valueless by exception)"); } } From 92b4018ce84eec5ccb23067a481dcb72afed1706 Mon Sep 17 00:00:00 2001 From: Liss Heidrich <31625940+liss-h@users.noreply.github.com> Date: Wed, 6 May 2026 15:00:16 +0200 Subject: [PATCH 5/7] add tuple_to_type_list --- include/dice/template-library/type_list.hpp | 19 +++++++++++++++++++ tests/tests_type_list.cpp | 10 ++++++++++ 2 files changed, 29 insertions(+) diff --git a/include/dice/template-library/type_list.hpp b/include/dice/template-library/type_list.hpp index d1799b7..29f5e69 100644 --- a/include/dice/template-library/type_list.hpp +++ b/include/dice/template-library/type_list.hpp @@ -506,6 +506,25 @@ namespace dice::template_library::type_list { using integer_sequence_to_type_list_t = typename integer_sequence_to_type_list::type; + /** + * Convert a tuple-like thing into a type list of its component types. + */ + template + struct tuple_to_type_list; + + template + requires requires { + { std::tuple_size_v } -> std::convertible_to; + } + struct tuple_to_type_list { + using type = decltype([](std::index_sequence) { + return type_list...>{}; + }(std::make_index_sequence>{})); + }; + + template + using tuple_to_type_list_t = typename tuple_to_type_list::type; + /** * A marker type to indicate a failed operation * when using opt diff --git a/tests/tests_type_list.cpp b/tests/tests_type_list.cpp index ee48ef3..7461989 100644 --- a/tests/tests_type_list.cpp +++ b/tests/tests_type_list.cpp @@ -302,6 +302,16 @@ TEST_SUITE("type_list") { static_assert(std::is_same_v, expected_iseq_tl>); } + TEST_CASE("tuple_to_type_list") { + using empty_tuple = std::tuple<>; + using pair = std::pair; + using tuple = std::tuple; + + static_assert(std::is_same_v, empty_t>); + static_assert(std::is_same_v, tl::type_list>); + static_assert(std::is_same_v, tl::type_list>); + } + TEST_CASE("for_each") { using t1 = tl::type_list; From a7e22e9f447c3cb19ffe49b97e6f94885fdc3c29 Mon Sep 17 00:00:00 2001 From: Liss Heidrich <31625940+liss-h@users.noreply.github.com> Date: Wed, 6 May 2026 15:10:57 +0200 Subject: [PATCH 6/7] implement flatten --- include/dice/template-library/type_list.hpp | 16 ++++++++++++++++ tests/tests_type_list.cpp | 7 +++++++ 2 files changed, 23 insertions(+) diff --git a/include/dice/template-library/type_list.hpp b/include/dice/template-library/type_list.hpp index 29f5e69..cf843cc 100644 --- a/include/dice/template-library/type_list.hpp +++ b/include/dice/template-library/type_list.hpp @@ -293,6 +293,22 @@ namespace dice::template_library::type_list { using filter_t = typename filter::type; + /** + * Flatten a type list of type lists of types into a type list of types. + * @tparam TL type list of type lists + */ + template + struct flatten; + + template + struct flatten> { + using type = concat_t; + }; + + template + using flatten_t = typename flatten::type; + + namespace detail_generate { template struct generate_impl; diff --git a/tests/tests_type_list.cpp b/tests/tests_type_list.cpp index 7461989..0942084 100644 --- a/tests/tests_type_list.cpp +++ b/tests/tests_type_list.cpp @@ -159,6 +159,13 @@ TEST_SUITE("type_list") { static_assert(std::is_same_v, tl::type_list>); } + TEST_CASE("flatten") { + static_assert(std::is_same_v, empty_t>); + static_assert(std::is_same_v>, empty_t>); + static_assert(std::is_same_v, empty_t, tl::type_list>>, tl::type_list>); + static_assert(std::is_same_v>>>, tl::type_list>>); + } + TEST_CASE("generate") { static_assert(std::is_same_v, empty_t>); From e3e943d5af846397397bc93503cb2642f80d7926 Mon Sep 17 00:00:00 2001 From: Nikolaos Karalis Date: Thu, 7 May 2026 17:38:01 +0200 Subject: [PATCH 7/7] fix explicit formatter --- tests/tests_variant2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests_variant2.cpp b/tests/tests_variant2.cpp index 1e0401a..d478768 100644 --- a/tests/tests_variant2.cpp +++ b/tests/tests_variant2.cpp @@ -43,7 +43,7 @@ struct std::formatter { } template - auto format(make_valueless, Ctx &format_ctx) const { + auto format(make_valueless const &, Ctx &format_ctx) const { return std::format_to(format_ctx.out(), "make_valueluess"); } };