boost :: variant - 为什么"const char*"转换为"bool"?

Mey*_*sam 18 c++ boost boost-variant

我已经宣布boost::variant它接受三种类型:string,boolint.以下代码显示我的变体接受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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

type:other - > 1
type:string - > some string

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

typedef variant<string, int> MyVariant;
Run Code Online (Sandbox Code Playgroud)

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

type:string - > some string
type:string - > some string

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

Gor*_*pik 13

这与boost::variantC++选择要应用的转换的顺序无关.在尝试使用用户定义的转换之前(请记住,这std::string是用户定义的类),编译器将尝试内置转换.有没有内置的转换,从const char*int,但按照标准§4.12:

[...]指针类型的prvalue可以转换为bool类型的prvalue.

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

  • 今天,这只是给我带来了一对重载方法,一个重载了一个“ bool”,另一个重载了“ const std :: string&”。不幸的! (2认同)

Ste*_*sop 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");
}
Run Code Online (Sandbox Code Playgroud)

输出:

bool
Run Code Online (Sandbox Code Playgroud)

我不知道如何改变Variant的构造函数[编辑:正如James所说,你可以编写另一个在其实现中使用Variant的类.然后你可以提供一个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");
}
Run Code Online (Sandbox Code Playgroud)

输出:

string
Run Code Online (Sandbox Code Playgroud)

不幸的是现在你必须写bar(MyBool(true))而不是foo(true).即使在你的变型的情况更糟糕string/bool/int,如果你只是将其更改为的变体string/MyBool/int,然后MyVariant(true)将调用int构造函数.

  • 要完成解释:存在从任何指针类型到`bool`的隐式转换,并且总是选择内置隐式转换而不是用户定义的转换.(将`char*`转换为`std :: string`计为用户定义.)至于更改构造函数,可以将该类包装在另一个类中,也可以从中派生.根据具体情况,其中一个可能适合也可能不适合; 两者都有一些缺点. (9认同)