【问题标题】:boost::variant implicit cast to stringboost::variant 隐式转换为字符串
【发布时间】:2015-06-23 16:38:38
【问题描述】:

我有一个不同类型的 boost::variant,其中一个是 (const) void 指针,另一个是字符串。

boost::variant<std::string, void const*>;

问题是,如果我想将它与 c 字符串一起使用,它会将其转换为 void 指针而不是字符串。

boost::variant<std::string, void const*> foo;
foo = "bar";
std::cout << foo.which(); // prints 1 -> void const*

如果我删除指针的常量,它会将它转换为字符串。

boost::variant<std::string, void*> foo; // no const pointer
foo = "bar";
std::cout << foo.which(); // prints 0 -> string

有没有一种简单的方法可以让 boost::variant 将 c-string 隐式转换为 std::string?

更新

我知道我可以使用以下方式进行显式转换:

foo = std::string("bar");

但我想避免显式转换。

【问题讨论】:

  • foo = std::string("bar"); 怎么样?见ideone.com/kgK2gm
  • @m.s.对不起,我忘了提到我不想一直明确地投射它。我会更新我的问题。
  • 使用 C++14,foo = "bar"s;?
  • 那就更糟了。如果你有一个variant&lt;std::string, bool&gt;,并且你用字符串初始化它,你会得到一个布尔值。

标签: c++ implicit-conversion boost-variant


【解决方案1】:

您可以通过从boost::variant 继承来提供自己的变体模板。 从const char*std::string的正确转换是通过重载operator=实现的:

#include <iostream>
#include <string>
#include <boost/variant.hpp>

template <typename... Types>
struct my_variant : public boost::variant<Types...>
{
    using boost::variant<Types...>::variant;

    auto operator=(const char* rhs)
    {
        return boost::variant<Types...>::operator=(std::string(rhs));
    }
};

int main() 
{
    my_variant<std::string, void const*> foo;
    foo = "bar";
    std::cout << foo.which(); 
    return 0;
}

根据需要输出“0”。

现场示例:https://ideone.com/ZppUla

通过使用指定类型映射的特征类可以更加概括这个想法:

template <template <typename> class conv_traits, typename... Types>
struct my_variant : public boost::variant<Types...>
{
    using boost::variant<Types...>::variant;

    template <typename T>
    auto operator=(T rhs)
    {
        return boost::variant<Types...>::operator=(static_cast<typename conv_traits<T>::type>(rhs));
    }
};

template <typename T>
struct conversion_traits
{
    typedef T type;
};

template <>
struct conversion_traits<const char*>
{
    typedef std::string type;
};

my_variant<conversion_traits, std::string, void const*> foo;

现场示例:https://ideone.com/AXUqTv

【讨论】:

  • 哦,你的解决方案比我的好得多。我删除我的支持这个。
  • @Ike不要删,也有效
  • 啊,好吧——虽然我认为这做得更好,并且已经推广到任何 boost::variant 实例化——很好。
  • 不幸的是,我使用 vs2013 并且没有 c++14 合规性。但我调整了你的答案并且它有效。谢谢。
【解决方案2】:

据我所知,没有办法直接执行此操作,但您可以使用包装器解决它。基本款(随心所欲地修饰,随心所欲地概括):

struct VariantWrapper
{
    template <class T>
    VariantWrapper& operator=(const T& val)
    {
        var = val;
        return *this;
    }

    template <int N>
    VariantWrapper& operator=(const char(&str)[N])
    {
        var = std::string(str);
        return *this;
    }

    boost::variant<std::string, void const*> var;
};

VariantWrapper bar;
bar = "foo";
std::cout << bar.var.which();

以上述方式执行此操作会将模板匹配限制为仅文本字符串和字符数组,但仍允许您使用 const char* 做一些不同的事情。虽然如果你想匹配所有适合 c-string 类别的东西,你可以使用 const char*

【讨论】:

    【解决方案3】:

    您可以从 boost::variant&lt;std::string, void const*&gt; 派生自己的类并提供隐式 const char* 和字符串构造函数。

    【讨论】:

      【解决方案4】:

      可以用xnode解决(类在某些方面类似于boost::variant,在其他方面类似于boost::any):

      using namespace std;
      xnode value = xnode::value_of("bar");
      cout << "type: " << value.type().name() << ", value: " << value.get_as<string>() << endl;
      

      在这个类中有明确的字符串字面量(数组)转换路径。

      见:https://github.com/vpiotr/xnode

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-24
        • 1970-01-01
        • 1970-01-01
        • 2017-11-09
        相关资源
        最近更新 更多