我有一个名为
foo_t
的班级,其中有一个名为 bar
的成员,它可以是 std::string
、int
、std::vector<double>
等类型中的任何一种。我希望能够询问 foo_t
bar
已分配给哪种类型。我决定使用std::variant
。
我已经写了一个解决方案,但我不确定这是否是 std::variant 的一个很好的用途。我不确定这是否重要,但我预计类型列表将来可能会变得更大。我创建了一个枚举类来存储分配给 std::variant 的类型。我的第一个实现也可以在 wandbox:
上找到#include <iostream>
#include <variant>
#include <vector>
#include <string>
enum foo_kind_t {
double_list,
name_tag,
number,
unknown
};
template <typename val_t>
struct get_foo_kind_t {
constexpr static foo_kind_t value = unknown;
};
template <>
struct get_foo_kind_t<int> {
constexpr static foo_kind_t value = number;
};
template <>
struct get_foo_kind_t<std::string> {
constexpr static foo_kind_t value = name_tag;
};
template <>
struct get_foo_kind_t<std::vector<double>> {
constexpr static foo_kind_t value = double_list;
};
class foo_t {
public:
foo_t(): kind(unknown) {}
template <typename val_t>
void assign_bar(const val_t &val) {
static_assert(get_foo_kind_t<val_t>::value != unknown, "unsupported assignment");
kind = get_foo_kind_t<val_t>::value;
bar = val;
}
foo_kind_t get_kind() {
return kind;
}
template <typename val_t>
val_t get_bar() {
if (get_foo_kind_t<val_t>::value != kind) {
throw std::runtime_error("wrong kind");
}
return std::get<val_t>(bar);
}
private:
foo_kind_t kind;
std::variant<
int,
std::string,
std::vector<double>
> bar;
};
template <typename val_t>
void print_foo(foo_t &foo) {
std::cout << "kind: " << foo.get_kind() << std::endl;
std::cout << "value: " << foo.get_bar<val_t>() << std::endl << std::endl;
}
int main(int, char*[]) {
// double_list
foo_t b;
std::vector<double> b_val({ 1.0, 1.1, 1.2 });
b.assign_bar(b_val);
std::cout << "kind: " << b.get_kind() << std::endl;
std::cout << "value: vector size: " << b.get_bar<std::vector<double>>().size() << std::endl << std::endl;
// name_tag
foo_t d;
std::string d_val("name");
d.assign_bar(d_val);
print_foo<std::string>(d);
// number
foo_t c;
int c_val = 99;
c.assign_bar(c_val);
print_foo<int>(c);
// unknown
foo_t a;
std::cout << a.get_kind() << std::endl;
return 0;
}
这是一个好方法吗?有没有办法获得更好的性能?有没有一种方法可以减少编写代码的次数呢?有没有不需要C++17的方法?
如果你只需要问“这是X型的变种吗?”对于单个类型 X,那么我建议您更喜欢
std::holds_alternative
而不是 std::variant::index
,因为该行代码更易于阅读,并且如果变体中类型的索引发生变化,则无需更新未来。
示例:
if (std::holds_alternative<X>(my_variant)) {
std::cout << "Variant is of type X" << std::endl;
}
std::variant::index
在运行时检查存储的类型。
有一个带有类型特征的解决方案
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
using MyVariant = std::variant<int, std::string>;
enum class MyVariantType { integer, string };
template <MyVariantType Type, typename T> struct is_variant_type : std::false_type {};
template <> struct is_variant_type<MyVariantType::integer, int > : std::true_type {};
template <> struct is_variant_type<MyVariantType::string , std::string> : std::true_type {};
template<MyVariantType VT>
bool check_variant_type(const MyVariant& myvar)
{
return std::visit([&](const auto& arg) {
return is_variant_type<VT, std::decay_t<decltype(arg)>>::value;
}, myvar);
}
int main(int argc, char* argv[])
{
MyVariant a = int(10);
MyVariant b = "Hello";
std::cout << check_variant_type<MyVariantType::integer>(a);
std::cout << check_variant_type<MyVariantType::integer>(b);
std::cout << check_variant_type<MyVariantType::string>(a);
std::cout << check_variant_type<MyVariantType::string>(b);
return 0;
}