boost::variant - 为啥“const char*”转换为“bool”?
Posted
技术标签:
【中文标题】boost::variant - 为啥“const char*”转换为“bool”?【英文标题】:boost::variant - why is "const char*" converted to "bool"?boost::variant - 为什么“const char*”转换为“bool”? 【发布时间】:2012-11-07 11:15:37 【问题描述】:我声明了一个boost::variant
,它接受三种类型:string
、bool
和int
。以下代码显示我的变体接受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;
输出:
类型:其他 -> 1 类型:字符串 -> 一些字符串
如果我从 MyVariant 中删除 bool 类型并将其更改为:
typedef variant<string, int> MyVariant;
const char*
不再转换为 bool
。这次它被转换为string
,这是新的输出:
类型:字符串 -> 一些字符串 类型:字符串 -> 一些字符串
这表示variant
尝试先将其他类型转换为bool
,然后再转换为string
。如果类型转换是不可避免的并且应该总是发生,有没有办法给string
的转换提供更高的优先级?
【问题讨论】:
【参考方案1】:这与boost::variant
无关,而是与 C++ 选择要应用的转换的顺序有关。在尝试使用用户定义的转换之前(请记住,std::string
是用于此目的的用户定义的类),编译器将尝试内置转换。没有从const char*
到int
的内置转换,但根据标准中的§4.12:
[...] 指针 [...] 类型的纯右值可以转换为 bool 类型的纯右值。
因此编译器很乐意将您的const char*
转换为bool
,并且永远不会考虑将其转换为std::string
。
更新:看起来这个明显不需要的转换正在修复。你可以找到修复here的技术解释。
【讨论】:
今天这对我来说是一对重载的方法,一个是bool
,另一个是const std::string&
。不幸!【参考方案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
【讨论】:
以上是关于boost::variant - 为啥“const char*”转换为“bool”?的主要内容,如果未能解决你的问题,请参考以下文章
将由 boost::variant 聚合的类型的对象传递给接受该 boost::variant 的函数
如何返回由 boost::variant 返回类型中包含的类型的子集组成的 boost::variant