New-Style Union: std::variant
¶
Problems With C Unions, And C++ Types¶
union
with C++ can be gotten rightNeed to call destructors explicitly
Other weirdnesses
⟶ no!
⟶
std::variant
Instantiation, Default Initialization, Member Access¶
#include <gtest/gtest.h>
#include <variant>
TEST(variant_suite, default_ctor)
{
std::variant<int, float> v; // <--- default: int{}
ASSERT_EQ(std::get<int>(v), 0); // <--- by-type: does not fail
ASSERT_EQ(std::get<0>(v), 0); // <--- by-position
ASSERT_EQ(v.index(), 0); // <--- which position does it hold?
ASSERT_TRUE(std::holds_alternative<int>(v)); // <--- which type does it hold?
v = 36.5f; // <--- now has float
// ...
ASSERT_FLOAT_EQ(std::get<float>(v), 36.5);
ASSERT_FLOAT_EQ(std::get<1>(v), 36.5);
ASSERT_EQ(v.index(), 1);
ASSERT_TRUE(std::holds_alternative<float>(v));
}
Non-Default Initialization¶
#include <gtest/gtest.h>
#include <variant>
TEST(variant_suite, converting_ctor)
{
std::variant<int, float> v{36.5f}; // <--- holds float
ASSERT_FLOAT_EQ(std::get<float>(v), 36.5);
ASSERT_FLOAT_EQ(std::get<1>(v), 36.5);
ASSERT_EQ(v.index(), 1);
}
Accessing Non-Current Member: std::bad_variant_access
¶
#include <gtest/gtest.h>
#include <variant>
TEST(variant_suite, bad_access)
{
std::variant<int, float> v{42};
try {
std::get<float>(v);
}
catch (const std::bad_variant_access&) {}
}
#include <gtest/gtest.h>
#include <variant>
struct Visitor
{
Visitor() : int_seen{false}, float_seen{false} {}
void operator()(int) { int_seen = true; }
void operator()(float) { float_seen = true; }
bool int_seen, float_seen;
};
TEST(variant_suite, visit)
{
std::variant<int, float> v;
Visitor vis;
std::visit(vis, v);
ASSERT_TRUE(vis.int_seen);
v = 36.5f;
}
Non-Throwing Accessor: std::get_if<>
¶
Exceptions are bad (at least in Embedded)
⟶ back to pointers 🤘
#include <gtest/gtest.h>
#include <variant>
TEST(variant_suite, get_if)
{
int tmp[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
(void)tmp;
std::variant<int, float> v{42};
const int* pi = std::get_if<int>(& /*REALLY!*/ v);
ASSERT_NE(pi, nullptr);
ASSERT_EQ(*pi, 42);
const float* pf = std::get_if<float>(&v);
ASSERT_EQ(pf, nullptr);
}
And Non-Fundamental Types?¶
#include <gtest/gtest.h>
#include <string>
#include <variant>
TEST(variant_suite, string_charp)
{
std::variant<std::string, const char*> v;
ASSERT_EQ(std::get<std::string>(v), std::string());
const char* s = "blah";
v = s;
ASSERT_EQ(std::get<const char*>(v), s);
v = "blah";
ASSERT_EQ(std::get_if<std::string>(&v), nullptr);
}
#include <gtest/gtest.h>
#include <variant>
struct Foo
{
Foo() = delete;
Foo(void*) {}
};
TEST(variant_suite, no_default_ctor)
{
// std::variant<Foo> v; // <--- error: no default ctor
std::variant<Foo> v{nullptr}; // <--- OK
(void)v;
}