为什么我的变体将 std::string 转换为布尔值?
Why does my variant convert a std::string to a bool?
我的 std::variant
可以为空 (std::monostate
),包含一个 int
、一个 std::string
或一个 bool
.
当我想给它提供一个字符串时,给定为 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
s,所以我想抓住这一点。否则它将成为错误的来源。我创建了模板辅助函数来检查 char*
是否已通过,如果是,则生成 std::string。效果很好。感谢帮助简化此过程!
编辑 2
通过将 std::monostate
声明为默认 parameter/type,它甚至可以在不带任何参数调用 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);
}
"hello"
不是 std::string
,它是 const char *
,它可以隐式转换为 bool 以及用于构造 std::string
。
换句话说,这很好用:
int main() {
bool b = "foo";
(void)b;
}
正如@aschepler 在评论中提到的:
The implicit conversion from const char*
to bool
is preferred over the user-defined conversion from const char*
to std::string
. int
is not an option at all.
"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;
我的 std::variant
可以为空 (std::monostate
),包含一个 int
、一个 std::string
或一个 bool
.
当我想给它提供一个字符串时,给定为 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
s,所以我想抓住这一点。否则它将成为错误的来源。我创建了模板辅助函数来检查 char*
是否已通过,如果是,则生成 std::string。效果很好。感谢帮助简化此过程!
编辑 2
通过将 std::monostate
声明为默认 parameter/type,它甚至可以在不带任何参数调用 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);
}
"hello"
不是 std::string
,它是 const char *
,它可以隐式转换为 bool 以及用于构造 std::string
。
换句话说,这很好用:
int main() {
bool b = "foo";
(void)b;
}
正如@aschepler 在评论中提到的:
The implicit conversion from
const char*
tobool
is preferred over the user-defined conversion fromconst char*
tostd::string
.int
is not an option at all.
"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;