From e6918187568dbd01842d8d1d2c808ce16a894239 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 21 Apr 2024 13:54:28 +0200 Subject: Adding upstream version 18.2.2. Signed-off-by: Daniel Baumann --- src/test/test_any.cc | 812 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 812 insertions(+) create mode 100644 src/test/test_any.cc (limited to 'src/test/test_any.cc') diff --git a/src/test/test_any.cc b/src/test/test_any.cc new file mode 100644 index 000000000..82d4a43f1 --- /dev/null +++ b/src/test/test_any.cc @@ -0,0 +1,812 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2018 Adam C. Emerson + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License version 2, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include +#include + +#include "gtest/gtest.h" + +#include "include/any.h" + +using std::optional; +using std::bad_any_cast; + +using ceph::immobile_any; +using ceph::unique_any; +using ceph::shared_any; + +using ceph::make_immobile_any; +using ceph::make_unique_any; +using ceph::make_shared_any; + +using ceph::any_cast; +using std::swap; + +template +static void test_empty() { + A a; + EXPECT_FALSE(a.has_value()); + EXPECT_EQ(typeid(void), a.type()); + a.reset(); + EXPECT_FALSE(a.has_value()); + EXPECT_EQ(typeid(void), a.type()); + +} + +TEST(Empty, Immobile) { + static_assert(std::is_nothrow_default_constructible_v>); + test_empty>(); +} + +TEST(Empty, Unique) { + static_assert(std::is_nothrow_default_constructible_v); + test_empty(); +} + +TEST(Empty, Shared) { + static_assert(std::is_nothrow_default_constructible_v); + test_empty(); +} + +struct cmd_tattler { + static thread_local bool copied; + static thread_local bool moved; + static thread_local bool destructed; + + static void reset() { + copied = false; + moved = false; + destructed = false; + } + + cmd_tattler() noexcept = default; + ~cmd_tattler() noexcept { + if (destructed) { + std::terminate(); + } + destructed = true; + } + cmd_tattler(const cmd_tattler&) noexcept { + if (copied) { + std::terminate(); + } + copied = true; + } + cmd_tattler& operator =(const cmd_tattler&) noexcept { + if (copied) { + std::terminate(); + } + copied = true; + return *this; + } + + cmd_tattler(cmd_tattler&&) noexcept { + if (moved) { + std::terminate(); + } + moved = true; + } + cmd_tattler& operator =(cmd_tattler&&) noexcept { + if (moved) { + std::terminate(); + } + moved = true; + return *this; + } +}; + +thread_local bool cmd_tattler::copied = false; +thread_local bool cmd_tattler::moved = false; +thread_local bool cmd_tattler::destructed = false; + +struct not_noexcept { + not_noexcept() = default; + + not_noexcept(const not_noexcept&) noexcept(false) { + } + not_noexcept& operator =(const not_noexcept&) noexcept(false) { + return *this; + } + + not_noexcept(not_noexcept&&) noexcept(false) { + } + not_noexcept& operator =(not_noexcept&&) noexcept(false) { + return *this; + } + + template + explicit not_noexcept(Args&& ...) noexcept(false) { + } + + template + not_noexcept(std::initializer_list, Args&& ...) noexcept(false) { + } +}; + +template +static void test_value_CMD() { + { + cmd_tattler::reset(); + cmd_tattler c; + A a(c); + EXPECT_TRUE(cmd_tattler::copied); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(cmd_tattler), a.type()); + a.reset(); + EXPECT_TRUE(cmd_tattler::destructed); + EXPECT_FALSE(a.has_value()); + EXPECT_EQ(typeid(void), a.type()); + + cmd_tattler::reset(); + a = c; + EXPECT_TRUE(cmd_tattler::copied); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(cmd_tattler), a.type()); + + cmd_tattler::reset(); + a = c; + EXPECT_TRUE(cmd_tattler::copied); + EXPECT_TRUE(cmd_tattler::destructed); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(cmd_tattler), a.type()); + cmd_tattler::reset(); + a.reset(); + EXPECT_TRUE(cmd_tattler::destructed); + cmd_tattler::reset(); + } + { + cmd_tattler::reset(); + cmd_tattler c; + A a(std::move(c)); + EXPECT_TRUE(cmd_tattler::moved); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(cmd_tattler), a.type()); + a.reset(); + EXPECT_TRUE(cmd_tattler::destructed); + EXPECT_FALSE(a.has_value()); + EXPECT_EQ(typeid(void), a.type()); + + cmd_tattler::reset(); + a = std::move(c); + EXPECT_TRUE(cmd_tattler::moved); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(cmd_tattler), a.type()); + + cmd_tattler::reset(); + a = std::move(c); + EXPECT_TRUE(cmd_tattler::moved); + EXPECT_TRUE(cmd_tattler::destructed); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(cmd_tattler), a.type()); + cmd_tattler::reset(); + a.reset(); + EXPECT_TRUE(cmd_tattler::destructed); + cmd_tattler::reset(); + } + { + cmd_tattler::reset(); + A a(cmd_tattler{}); + EXPECT_TRUE(cmd_tattler::moved); + EXPECT_TRUE(cmd_tattler::destructed); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(cmd_tattler), a.type()); + + cmd_tattler::reset(); + a.reset(); + EXPECT_TRUE(cmd_tattler::destructed); + EXPECT_FALSE(a.has_value()); + EXPECT_EQ(typeid(void), a.type()); + + cmd_tattler::reset(); + a = cmd_tattler{}; + EXPECT_TRUE(cmd_tattler::moved); + EXPECT_TRUE(cmd_tattler::destructed); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(cmd_tattler), a.type()); + cmd_tattler::reset(); + a.reset(); + EXPECT_TRUE(cmd_tattler::destructed); + cmd_tattler::reset(); + } +} + + + +TEST(Value_CMD, Immobile) { + static_assert(std::is_nothrow_constructible_v< + immobile_any<1024>, const cmd_tattler&>); + static_assert(std::is_nothrow_assignable_v< + immobile_any<1024>, const cmd_tattler&>); + static_assert(std::is_nothrow_constructible_v< + immobile_any<1024>, cmd_tattler&&>); + static_assert(std::is_nothrow_assignable_v< + immobile_any<1024>, cmd_tattler&&>); + + static_assert(!std::is_nothrow_constructible_v< + immobile_any<1024>, const not_noexcept&>); + static_assert(!std::is_nothrow_assignable_v< + immobile_any<1024>, const not_noexcept&>); + static_assert(!std::is_nothrow_constructible_v< + immobile_any<1024>, not_noexcept&&>); + static_assert(!std::is_nothrow_assignable_v< + immobile_any<1024>, not_noexcept&&>); + + test_value_CMD>(); +} + +TEST(Value_CMD, Unique) { + static_assert(!std::is_nothrow_constructible_v< + unique_any, const cmd_tattler&>); + static_assert(!std::is_nothrow_assignable_v< + unique_any, const cmd_tattler&>); + static_assert(!std::is_nothrow_constructible_v< + unique_any, cmd_tattler&&>); + static_assert(!std::is_nothrow_assignable_v< + unique_any, cmd_tattler&&>); + + static_assert(!std::is_nothrow_constructible_v< + unique_any, const not_noexcept&>); + static_assert(!std::is_nothrow_assignable_v< + unique_any, const not_noexcept&>); + static_assert(!std::is_nothrow_constructible_v< + unique_any, not_noexcept&&>); + static_assert(!std::is_nothrow_assignable_v< + unique_any, not_noexcept&&>); + + test_value_CMD(); +} + +TEST(Value_CMD, Shared) { + static_assert(!std::is_nothrow_constructible_v< + shared_any, const cmd_tattler&>); + static_assert(!std::is_nothrow_assignable_v< + shared_any, const cmd_tattler&>); + static_assert(!std::is_nothrow_constructible_v< + shared_any, cmd_tattler&&>); + static_assert(!std::is_nothrow_assignable_v< + shared_any, cmd_tattler&&>); + + static_assert(!std::is_nothrow_constructible_v< + shared_any, const not_noexcept&>); + static_assert(!std::is_nothrow_assignable_v< + shared_any, const not_noexcept&>); + static_assert(!std::is_nothrow_constructible_v< + shared_any, not_noexcept&&>); + static_assert(!std::is_nothrow_assignable_v< + shared_any, not_noexcept&&>); + + test_value_CMD(); +} + +template +static void test_move() { + { + A a(5); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(int), a.type()); + + A b(std::move(a)); + EXPECT_TRUE(b.has_value()); + EXPECT_EQ(typeid(int), b.type()); + + EXPECT_FALSE(a.has_value()); + EXPECT_EQ(typeid(void), a.type()); + } + { + cmd_tattler::reset(); + A a(cmd_tattler{}); + + A b(5); + EXPECT_TRUE(b.has_value()); + EXPECT_EQ(typeid(int), b.type()); + cmd_tattler::reset(); + + a = std::move(b); + EXPECT_TRUE(cmd_tattler::destructed); + + EXPECT_FALSE(b.has_value()); + EXPECT_EQ(typeid(void), b.type()); + + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(int), a.type()); + } +} + +static_assert(!std::is_move_constructible_v>); +static_assert(!std::is_move_assignable_v>); + +TEST(Move, Unique) { + static_assert(std::is_nothrow_move_constructible_v); + static_assert(std::is_nothrow_move_assignable_v); + + test_move(); +} + +TEST(Move, Shared) { + static_assert(std::is_nothrow_move_constructible_v); + static_assert(std::is_nothrow_move_assignable_v); + + test_move(); +} + +template +static void test_copy() { + { + const A a(5); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(int), a.type()); + + A b(a); + EXPECT_TRUE(b.has_value()); + EXPECT_EQ(typeid(int), b.type()); + + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(int), a.type()); + + EXPECT_EQ(any_cast(a), any_cast(b)); + } + { + cmd_tattler::reset(); + A a(cmd_tattler{}); + + const A b(5); + EXPECT_TRUE(b.has_value()); + EXPECT_EQ(typeid(int), b.type()); + cmd_tattler::reset(); + + a = b; + EXPECT_TRUE(cmd_tattler::destructed); + + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(int), a.type()); + + EXPECT_TRUE(b.has_value()); + EXPECT_EQ(typeid(int), b.type()); + + EXPECT_EQ(any_cast(a), any_cast(b)); + } +} + +static_assert(!std::is_copy_constructible_v>); +static_assert(!std::is_copy_assignable_v>); + +static_assert(!std::is_copy_constructible_v); +static_assert(!std::is_copy_assignable_v); + +TEST(Copy, Shared) { + static_assert(std::is_nothrow_copy_constructible_v); + test_copy(); +} + +struct unmoving { + optional a; + + unmoving() noexcept {} + + template + explicit unmoving(Args&& ...args) noexcept + : a(sizeof...(Args)) {} + + template + explicit unmoving(std::initializer_list l) noexcept + : a(-l.size()) {} + + template + unmoving(std::initializer_list l, Args&& ...args) noexcept + : a(-l.size() * sizeof...(Args)) {} + + unmoving(const unmoving&) = delete; + unmoving& operator =(const unmoving&) = delete; + + unmoving(unmoving&&) = delete; + unmoving& operator =(unmoving&&) = delete; +}; + +template +static void test_unmoving_pack_il() { + // Nothing! + { + const A a(std::in_place_type); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_FALSE(any_cast(a).a); + } + { + cmd_tattler::reset(); + A a(cmd_tattler{}); + + cmd_tattler::reset(); + a.template emplace(); + EXPECT_TRUE(cmd_tattler::destructed); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_FALSE(any_cast(a).a); + } + + // Pack! + { + const A a(std::in_place_type, nullptr, 5, 3.1); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_TRUE(any_cast(a).a); + EXPECT_EQ(3, *any_cast(a).a); + } + { + cmd_tattler::reset(); + A a(cmd_tattler{}); + + cmd_tattler::reset(); + a.template emplace(nullptr, 5, 3.1); + EXPECT_TRUE(cmd_tattler::destructed); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_EQ(3, *any_cast(a).a); + } + + // List! + { + const A a(std::in_place_type, {true, true, true, true}); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_TRUE(any_cast(a).a); + EXPECT_EQ(-4, *any_cast(a).a); + } + { + cmd_tattler::reset(); + A a(cmd_tattler{}); + + cmd_tattler::reset(); + a.template emplace({true, true, true, true}); + EXPECT_TRUE(cmd_tattler::destructed); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_EQ(-4, *any_cast(a).a); + } + + // List + pack!! + { + const A a(std::in_place_type, {true, true, true, true}, + nullptr, 5, 3.1); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_TRUE(any_cast(a).a); + EXPECT_EQ(-12, *any_cast(a).a); + } + { + cmd_tattler::reset(); + A a(cmd_tattler{}); + + cmd_tattler::reset(); + a.template emplace({true, true, true, true}, nullptr, 5, 3.1); + EXPECT_TRUE(cmd_tattler::destructed); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_EQ(-12, *any_cast(a).a); + } +} + +TEST(UmovingPackIl, Immobile) { + static_assert(std::is_nothrow_constructible_v, + std::in_place_type_t>); + static_assert(noexcept(immobile_any<1024>{}.emplace())); + + static_assert(std::is_nothrow_constructible_v, + std::in_place_type_t, std::nullptr_t, int, double>); + static_assert(noexcept(immobile_any<1024>{}.emplace( + nullptr, 5, 3.1))); + + static_assert(std::is_nothrow_constructible_v, + std::in_place_type_t, std::initializer_list>); + static_assert(noexcept(immobile_any<1024>{}.emplace( + {true, true, true, true}))); + + static_assert(std::is_nothrow_constructible_v, + std::in_place_type_t, std::initializer_list, + std::nullptr_t, int, double>); + static_assert(noexcept(immobile_any<1024>{}.emplace( + {true, true, true, true}, nullptr, 5, 3.1))); + + test_unmoving_pack_il>(); +} + +TEST(UmovingPackIl, Unique) { + static_assert(!std::is_nothrow_constructible_v>); + static_assert(!noexcept(unique_any{}.emplace())); + + static_assert(!std::is_nothrow_constructible_v, std::nullptr_t, int, double>); + static_assert(!noexcept(unique_any{}.emplace( + nullptr, 5, 3.1))); + + static_assert(!std::is_nothrow_constructible_v, std::initializer_list>); + static_assert(!noexcept(unique_any{}.emplace( + {true, true, true, true}))); + + static_assert(!std::is_nothrow_constructible_v, std::initializer_list, + std::nullptr_t, int, double>); + static_assert(!noexcept(unique_any{}.emplace( + {true, true, true, true}, nullptr, 5, 3.1))); + + test_unmoving_pack_il(); +} + +TEST(UmovingPackIl, Shared) { + static_assert(!std::is_nothrow_constructible_v>); + static_assert(!noexcept(shared_any{}.emplace())); + + static_assert(!std::is_nothrow_constructible_v, std::nullptr_t, int, double>); + static_assert(!noexcept(shared_any{}.emplace( + nullptr, 5, 3.1))); + + static_assert(!std::is_nothrow_constructible_v, std::initializer_list>); + static_assert(!noexcept(shared_any{}.emplace( + {true, true, true, true}))); + + static_assert(!std::is_nothrow_constructible_v, std::initializer_list, + std::nullptr_t, int, double>); + static_assert(!noexcept(shared_any{}.emplace( + {true, true, true, true}, nullptr, 5, 3.1))); + + test_unmoving_pack_il(); +} + +template +static void test_swap() { + A a(true); + ASSERT_TRUE(a.has_value()); + ASSERT_EQ(typeid(bool), a.type()); + ASSERT_EQ(true, any_cast(a)); + + A b(5); + ASSERT_TRUE(b.has_value()); + ASSERT_EQ(typeid(int), b.type()); + ASSERT_EQ(5, any_cast(b)); + + a.swap(b); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(int), a.type()); + EXPECT_EQ(5, any_cast(a)); + + EXPECT_TRUE(b.has_value()); + ASSERT_EQ(typeid(bool), b.type()); + ASSERT_EQ(true, any_cast(b)); + + swap(a,b); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(bool), a.type()); + EXPECT_EQ(true, any_cast(a)); + + EXPECT_TRUE(b.has_value()); + EXPECT_EQ(typeid(int), b.type()); + EXPECT_EQ(5, any_cast(b)); +} + +static_assert(!std::is_swappable_v>); + +TEST(Swap, Unique) { + static_assert(std::is_nothrow_swappable_v); + test_swap(); +} + +TEST(Swap, Shared) { + static_assert(std::is_nothrow_swappable_v); + test_swap(); +} + +template +static void test_cast() { + // Empty + { + A a; + EXPECT_EQ(nullptr, any_cast(&a)); + EXPECT_THROW({any_cast(a);}, bad_any_cast); + EXPECT_THROW({any_cast(a);}, bad_any_cast); + EXPECT_THROW({any_cast(std::move(a));}, bad_any_cast); + EXPECT_THROW({any_cast(std::move(a));}, bad_any_cast); + } + + // Constant Empty + { + const A a{}; + EXPECT_EQ(nullptr, any_cast(const_cast(&a))); + EXPECT_THROW({any_cast(a);}, bad_any_cast); + EXPECT_THROW({any_cast(a);}, bad_any_cast); + } + + // Filled! + { + A a(true); + EXPECT_TRUE(*any_cast(&a)); + EXPECT_EQ(nullptr, any_cast(&a)); + + EXPECT_TRUE(any_cast(a)); + EXPECT_THROW({any_cast(a);}, bad_any_cast); + + EXPECT_TRUE(any_cast(a)); + EXPECT_THROW({any_cast(a);}, bad_any_cast); + + EXPECT_TRUE(any_cast(std::move(a))); + EXPECT_THROW({any_cast(std::move(a));}, bad_any_cast); + + EXPECT_TRUE(any_cast(std::move(a))); + EXPECT_THROW({any_cast(std::move(a));}, bad_any_cast); + } + + // Constant filled + { + const A a(true); + EXPECT_TRUE(*any_cast(&a)); + EXPECT_EQ(nullptr, any_cast(&a)); + + EXPECT_TRUE(any_cast(a)); + EXPECT_THROW({any_cast(a);}, bad_any_cast); + + EXPECT_TRUE(any_cast(a)); + EXPECT_THROW({any_cast(a);}, bad_any_cast); + } + + // Move! + { + cmd_tattler::reset(); + A a(cmd_tattler{}); + cmd_tattler::reset(); + + auto q = any_cast(std::move(a)); + EXPECT_TRUE(cmd_tattler::moved); + cmd_tattler::reset(); + a.reset(); + cmd_tattler::reset(); + } + + // Move! Again! + { + cmd_tattler::reset(); + auto q = any_cast(A(std::in_place_type)); + EXPECT_TRUE(cmd_tattler::moved); + cmd_tattler::reset(); + } +} + +TEST(Cast, Immobile) { + test_cast>(); +} + +TEST(Cast, Unique) { + test_cast(); +} + +TEST(Cast, Shared) { + test_cast(); +} + +TEST(Make, Immobile) { + // Nothing! + { + auto a{make_immobile_any()}; + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_FALSE(any_cast(a).a); + } + + // Pack! + { + auto a(make_immobile_any(nullptr, 5, 3.1)); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_TRUE(any_cast(a).a); + EXPECT_EQ(3, *any_cast(a).a); + } + + // List! + { + auto a(make_immobile_any({true, true, true, true})); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_TRUE(any_cast(a).a); + EXPECT_EQ(-4, *any_cast(a).a); + } + + // List + pack!! + { + auto a{make_immobile_any({true, true, true, true}, + nullptr, 5, 3.1)}; + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_TRUE(any_cast(a).a); + EXPECT_EQ(-12, *any_cast(a).a); + } +} + +TEST(Make, Unique) { + // Nothing! + { + auto a{make_unique_any()}; + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_FALSE(any_cast(a).a); + } + + // Pack! + { + auto a(make_unique_any(nullptr, 5, 3.1)); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_TRUE(any_cast(a).a); + EXPECT_EQ(3, *any_cast(a).a); + } + + // List! + { + auto a(make_unique_any({true, true, true, true})); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_TRUE(any_cast(a).a); + EXPECT_EQ(-4, *any_cast(a).a); + } + + // List + pack!! + { + auto a{make_unique_any({true, true, true, true}, + nullptr, 5, 3.1)}; + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_TRUE(any_cast(a).a); + EXPECT_EQ(-12, *any_cast(a).a); + } +} + +TEST(Make, Shared) { + // Nothing! + { + auto a{make_shared_any()}; + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_FALSE(any_cast(a).a); + } + + // Pack! + { + auto a(make_shared_any(nullptr, 5, 3.1)); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_TRUE(any_cast(a).a); + EXPECT_EQ(3, *any_cast(a).a); + } + + // List! + { + auto a(make_shared_any({true, true, true, true})); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_TRUE(any_cast(a).a); + EXPECT_EQ(-4, *any_cast(a).a); + } + + // List + pack!! + { + auto a{make_shared_any({true, true, true, true}, + nullptr, 5, 3.1)}; + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(typeid(unmoving), a.type()); + EXPECT_TRUE(any_cast(a).a); + EXPECT_EQ(-12, *any_cast(a).a); + } +} -- cgit v1.2.3