19

我已声明 aboost::variant接受三种类型stringboolint. 以下代码显示我的变体接受const char*并将其转换为bool. boost::variant接受和转换不在其列表中的类型是正常行为吗?

#include <iostream>
#include "boost/variant/variant.hpp"
#include "boost/variant/apply_visitor.hpp"

using namespace std;
using namespace boost;

typedef variant<string, bool, int> MyVariant;

class TestVariant
    : public boost::static_visitor<>
{
public:
    void operator()(string &v) const
    {
        cout << "type: string -> " << v << endl;
    }
    template<typename U>
    void operator()(U &v)const
    {
        cout << "type: other -> " << v << endl;
    }
};

int main(int argc, char **argv) 
{
    MyVariant s1 = "some string";
    apply_visitor(TestVariant(), s1);

    MyVariant s2 = string("some string");
    apply_visitor(TestVariant(), s2);

    return 0;
}

输出:

类型:其他 -> 1
类型:字符串 -> 一些字符串

如果我从 MyVariant 中删除 bool 类型并将其更改为:

typedef variant<string, int> MyVariant;

const char*不再转换为bool. 这次它被转换为string,这是新的输出:

类型:字符串 -> 一些字符串
类型:字符串 -> 一些字符串

这表示variant尝试先将其他类型转换boolstring. 如果类型转换是不可避免的并且应该总是发生,有没有办法将转换赋予string更高的优先级?

4

3 回答 3

13

这与 无关boost::variant,而是与 C++ 选择要应用的转换的顺序有关。在尝试使用用户定义的转换之前(记住这std::string是一个用于此目的的用户定义的类),编译器将尝试内置转换。const char*没有从to的内置转换int,但根据标准中的 §4.12:

[...] 指针 [...] 类型的纯右值可以转换为 bool 类型的纯右值。

因此编译器很乐意将您转换const char*为 abool并且永远不会考虑将其转换为 a std::string

更新:看起来这个明显不需要的转换正在修复。您可以在此处找到该修复程序的技术说明。

于 2012-11-07T11:30:59.980 回答
12

我认为这与 没有什么特别的关系boost::variant,它与重载决议选择了哪个构造函数有关。重载函数也会发生同样的事情:

#include <iostream>
#include <string>

void foo(bool) {
    std::cout << "bool\n";
}

void foo(std::string) {
    std::cout << "string\n";
}

int main() {
    foo("hi");
}

输出:

bool

我不知道如何更改变体具有的构造函数[编辑:正如詹姆斯所说,您可以编写另一个在其实现中使用变体的类。然后你可以提供一个const char*做正确事情的构造函数。]

也许您可以更改 Variant 中的类型。另一个重载示例:

struct MyBool {
    bool val;
    explicit MyBool(bool val) : val(val) {}
};

void bar(MyBool) {
    std::cout << "bool\n";
}

void bar(const std::string &) {
    std::cout << "string\n";
}

int main() {
    bar("hi");
}

输出:

string

不幸的是,现在您必须编写bar(MyBool(true))而不是foo(true). 更糟糕的是string/bool/int,如果您只是将其更改为string/MyBool/intthen的变体,MyVariant(true)则会调用int构造函数。

于 2012-11-07T11:23:02.877 回答
0

我猜你想要使用的是字符串文字(不是 const char * 本身)。

然后,您可以尝试 std::string_literals(std::string 的 s-suffix)。

#include <iostream>
#include "boost/variant/variant.hpp"
#include "boost/variant/apply_visitor.hpp"

#include <string>
using namespace std::string_literals; // enables s-suffix for std::string literals

using namespace std;
using namespace boost;

typedef variant<string, bool, int> MyVariant;

class TestVariant
    : public boost::static_visitor<>
{
public:
    void operator()(string &v) const
    {
        cout << "type: string -> " << v << endl;
    }
    template<typename U>
    void operator()(U &v)const
    {
        cout << "type: other -> " << v << endl;
    }
};

int main(int argc, char **argv) 
{
    MyVariant s1 = "some string"s; // use s-suffix ("some string"s is std::string, not const char *
    apply_visitor(TestVariant(), s1);

    MyVariant s2 = string("some string");
    apply_visitor(TestVariant(), s2);

    return 0;
}

输出:

type: string -> some string
type: string -> some string
于 2021-07-22T19:06:46.833 回答