【问题标题】:Why does my variant convert a std::string to a bool?为什么我的变体将 std::string 转换为 bool?
【发布时间】:2017-10-20 12:59:40
【问题描述】:

我的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    
}

编辑 由于我的代码的用户可能没有明确地创建strings,我喜欢抓住它。否则,这将是错误的来源。我制作了模板助手函数来检查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);    
}

【问题讨论】:

  • 另一个要问的问题是,为什么std::stringbool 更受欢迎?两者都需要数组衰减和类型转换。
  • 查看我对stackoverflow.com/questions/44021989/… 的可爱回答,尤其是我使用模板的解决方法 ;-)。但是 Angew 使用用户定义的文字(如下)更可爱。
  • 简短回答:它没有,因为那不是你给它的std::string

标签: c++ c++17 variant


【解决方案1】:

"hello" 不是std::string,而是const char *,它可以隐式转换为布尔值,也可以用于构造std::string
换句话说,这很好用:

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

正如@aschepler 在 cmets 中提到的:

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

【讨论】:

  • 这里没有 UB。从const char*bool 的隐式转换优先于从const char*std::string 的用户定义转换。 int 根本不是一个选项。
  • @aschepler 谢谢,已修复。
【解决方案2】:

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

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

using namespace std::string_literals;

var contains_string = "hello"s;

【讨论】:

  • 为什么它没有选择int类型而不是bool
  • @skypjack 因为在 C++ 中没有隐式指向 int 转换的指针。
  • 确实有道理。谢谢你。 :-)
  • 是否有可能的解决方法来防止从const char* 转换为string 而无需明确说明?
猜你喜欢
  • 1970-01-01
  • 2021-02-28
  • 2021-06-01
  • 1970-01-01
  • 2021-11-29
  • 1970-01-01
  • 2016-01-28
相关资源
最近更新 更多