web-dev-qa-db-ja.com

ブーストバリアント:現在保持されているタイプを取得する方法

私が理解したように boost.variant のすべてのタイプは実際のタイプに解析されます(ブーストvariant<int, string> a; a="bla-bla"がコンパイル後にstring a; a="bla-bla"に変わるように意味します)どのタイプがブーストバリアントに入れられましたか?

私が試したもの:

#include <boost/variant.hpp>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>

int main()
{
    typedef boost::function<double (double x)> func0;
    typedef boost::function<double (double x, double y)> func1;
    typedef boost::variant<int, func0, func1> variant_func;
    func1 fn = std::plus<double>();
    variant_func v(fn);
    std::cout << boost::get<func1>(v)(1.0, 1.0) << std::endl; // this works
    //std::cout << boost::get<v::type>(v)(1.0, 1.0) << std::endl; // this does not compile with many errors
    // std::cout << (v)(1.0, 1.0) << std::endl; // this fails with Error    1   error C2064: term does not evaluate to a function taking 2 arguments

    std::cin.get();
    return 0;
}
41
myWallJSON

v.which()は、現在保持されているオブジェクトのタイプの0から始まるインデックスを返します。

オブジェクトを取得するとき、コードは(_get<T>_関数テンプレートを満たすために)静的型を使用して(効果的に)動的に型指定されたオブジェクトを参照する必要があります。

タイプをテストし(which()またはtype()を使用)、それに応じて分岐するか、静的ビジターを使用する必要があります。どちらの方法を選択しても、取得する静的型を明示的に指定する必要があり、動的型と一致する必要があります。そうしないと、例外がスローされます。

この問題を回避する方法の1つは、バリアント型を直接使用する代わりに、バリアント型を内部的に含むクラスを使用し、オブジェクトを最小限の手間で使用するために必要な暗黙の変換演算子を定義することです。

Dynamic C++ というプロジェクトを使用しており、この手法を使用しています。

32
Ferruccio

_boost.variant_には .type() function があり、RTTIを有効にしている場合、アクティブな型のtypeidを返すことができます。

静的な訪問者を定義して、バリアントのコンテンツのタイプに応じてアクションを実行することもできます。

_struct SomeVisitor : public boost::static_visitor<double>
{
    double operator()(const func0& f0) const { return f0(1.0); }
    double operator()(const func1& f1) const { return f1(1.0, 1.0); }
    double operator()(int integer) const { return integer; }
};
...
std::cout << boost::apply_visitor(SomeVisitor(), v) << std::endl;
_
18
kennytm

両方ともstd :: type_infoオブジェクトになる以下を使用できます。

  • boost :: variantのtype()メンバー関数、
  • 任意の型または型付き式に適用できるC++演算子typeid()

メンバー関数std :: type_info :: operator ==とともに、boost :: variantが現在保存している型を確認します。例えば、

boost::variant<int, bool, std::string> container;
container = "Hello world";

if (container.type() == typeid(std::string)) {
    std::cout << "Found a string: " << boost::get<std::string>(container);
}
else if (container.type() == typeid(int)) {
    std::cout << "Found an int: " << boost::get<int>(container);
}
10
richardr