【问题标题】:boost::variant - why is "const char*" converted to "bool"?boost::variant - 为什么“const char*”转换为“bool”?
【发布时间】:2012-11-07 11:15:37
【问题描述】:

我声明了一个boost::variant,它接受三种类型:stringboolint。以下代码显示我的变体接受const char* 并将其转换为boolboost::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 尝试先将其他类型转换为bool,然后再转换为string。如果类型转换是不可避免的并且应该总是发生,有没有办法给string的转换提供更高的优先级?

【问题讨论】:

    标签: c++ boost boost-variant


    【解决方案1】:

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

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

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

    更新:看起来这个明显不需要的转换正在修复。你可以找到修复here的技术解释。

    【讨论】:

    • 今天这对我来说是一对重载的方法,一个是bool,另一个是const std::string&amp;。不幸!
    【解决方案2】:

    我认为这与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
    

    我不知道如何更改 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");
    }
    

    输出:

    string
    

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

    【讨论】:

    • 为了完成你的解释:从任何指针类型到bool 都有一个隐式转换,并且总是优先选择内置隐式转换而不是用户定义的转换。 (char*std::string 的转换算用户自定义。) 至于改变构造函数,你可以将类包装在另一个类中,或者从它派生。根据上下文,其中之一可能合适,也可能不合适;两者都有一些缺点。
    • 我认为一种解决方案是从 MyVariant 中删除 bool 并改用 0 和 1 值。
    • @Meysam:是的。我考虑过推荐它,但后来我想你可能希望用0 初始化的MyVariant 与用false 初始化的MyVariant 不同。如果它们可以相同,只需删除bool。如果它们有不同的含义,那就没那么简单了。
    【解决方案3】:

    我猜你想使用的是字符串文字(不是 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-09
      • 1970-01-01
      • 1970-01-01
      • 2013-04-25
      相关资源
      最近更新 更多