为什么我的变体将std :: string转换为bool?

时间:2017-05-20 13:08:38

标签: c++ c++17 variant

我的std::variant可以为空(std::monostate),包含intstd::stringbool

当我想用一个字符串(以var = "this is my string"为单位)提供它时,它会转换为bool而不是字符串。如果我明确声明了类型,它就可以var = std::string("this is my string")。为什么会这样,我能做些什么来避免呢?

#include <string>
#include <variant>
#include <iostream>

int main()
{
    using var = std::variant<std::monostate, int, std::string, bool>;

    var contains_nothing;    
    var contains_int = 5;
    var contains_string = "hello";
    var contains_expl_string = std::string("explicit hello");
    var contains_bool = false;

    auto visitor = [](auto&& arg){
            using T = std::decay_t<decltype(arg)>;
            if constexpr (std::is_same<T, std::monostate>())
                std::cout<<"nothing\n";
            else if constexpr (std::is_same<T, int>())  
                std::cout<<"int: "<<arg<<"\n";
            else if constexpr (std::is_same<T, std::string>())  
                std::cout<<"string: "<<arg<<"\n";
            else if constexpr (std::is_same<T, bool>())  
                std::cout<<"bool: "<<arg<<"\n";
            else 
                std::cout<<"Visitor is not exhaustive\n";
        };

    std::visit(visitor, contains_nothing);       // nothing
    std::visit(visitor, contains_int);           // int: 5
    std::visit(visitor, contains_string);        // bool: 1
    std::visit(visitor, contains_expl_string);   // string: explicit hello
    std::visit(visitor, contains_bool);          // bool: 0    
}

修改 由于我的代码的用户可能没有明确地生成string,我喜欢抓住它。否则它将成为错误的来源。我创建了模板辅助函数来检查是否已经传递了char*,如果是,则创建一个std :: string。效果很好。欢迎使这更简单的帮助!

编辑2 通过将std::monostate声明为默认参数/类型,它甚至可以在没有任何参数的情况下调用make_var时起作用。

#include <string>
#include <variant>
#include <iostream>

using var = std::variant<std::monostate, int, std::string, bool>;

template<typename T = std::monostate>
var make_var(T value = std::monostate())
{
    if constexpr (std::is_same<typename std::remove_const<typename std::decay<T>::type>::type, const char*>())
        return std::string(value);
    return value;
}

int main()
{
    auto contains_nothing = make_var();    
    auto contains_int = make_var(3);
    auto contains_string = make_var("hello");
    auto contains_expl_string = make_var(std::string("excplicit hello"));
    var contains_bool = make_var(false);

    auto visitor = [](auto&& arg){
            using T = std::decay_t<decltype(arg)>;
            if constexpr (std::is_same<T, std::monostate>())
                std::cout<<"nothing\n";
            else if constexpr (std::is_same<T, int>())  
                std::cout<<"int: "<<arg<<"\n";
            else if constexpr (std::is_same<T, std::string>())  
                std::cout<<"string: "<<arg<<"\n";
            else if constexpr (std::is_same<T, bool>())  
                std::cout<<"bool: "<<arg<<"\n";
            else 
                std::cout<<"Visitor is not exhaustive\n";
        };

    std::visit(visitor, contains_nothing);
    std::visit(visitor, contains_int);
    std::visit(visitor, contains_string);
    std::visit(visitor, contains_expl_string);
    std::visit(visitor, contains_bool);    
}

2 个答案:

答案 0 :(得分:28)

"hello"的类型为const char [6],其衰减为const char *。从const char *bool的转换是内置转换,而从const char *std::string的转换是用户定义的转换,这意味着执行前者。

由于您使用的是C ++&gt; = 14,因此您可以使用文字后缀s来表示std::string字面值:

using namespace std::string_literals;

var contains_string = "hello"s;

答案 1 :(得分:4)

"hello"不是std::string,它是const char *,可以隐式转换为bool,也可以用于构建std::string。 换句话说,这很好用:

int main() {
    bool b = "foo";
    (void)b;
}

如@aschepler的评论所述:

  

const char*bool的隐式转换优先于用户定义的从const char*std::string的转换。 int根本不是一个选项。