C++17 std::variant 简单使用

std::variant应当是用来替代union来使用的,后者从C时代就有了,但是它缺乏类型安全的保障。boost库很早之前就有了实现(其实从C++11开始,感觉boost不知道多少东西被借鉴走了)。
std::variant的类长这个样子:

template <class... Types>
class variant;

Usage

使用起来也是比较方便的

std::variant<int, double> v1;
v1 = 1; // activate the "int" member
assert(v1.index() == 0);
assert(std::get<0>(v1) == 1);

v1 = 3.14; // activate the "double" member
assert(v1.index() == 1);
assert(std::get<1>(v1) == 3.14);
assert(std::get<double>(v1) == 3.14);

assert(std::holds_alternative<int>(v1) == false);
assert(std::holds_alternative<double>(v1) == true);

assert(std::get_if<int>(&v1) == nullptr);
assert(*std::get_if<double>(&v1) == 3.14);

上面代码里的几个好用的constexpr函数:

  • std::get<>:可以传入index或是type。如果index或者类型不对的话,会跑出std::bad_variant_access异常;
  • std::get_if<>:这个是不抛异常的版本。注意参数和返回值类型都是指针——如果没有有效元素,那就会返回nullptr;
  • std::holds_alternative<Type>:判断一个Type在不在定义的variant参数类里面;

Visiting variants

如果要根据当前存储的类型来对variant对象做一些操作,第一会想到写一些if语句

if (std::holds_alternative<int>(v1) == true) {
  // handle int value
}
else {
  // handle double value
}

但是如果variant的可选类型比较多的话,定义一个Visitor类会有助于按类型来执行操作,逻辑会显得清晰

struct Visitor {
  double operator() (double d) { return d; }
  double operator() (int i) { return double(i); }
};

void show(std::variant<double, int> v) {
  std::cout >> std::visit(Visitor{}, v) << std::endl;
}

void test() {
  show(3.14);
  show(1);
}

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.