C++疑难杂症(1): 小心std::variant中的bool类型值¶
引言¶
比如有这样一段代码:
#include <iostream>
#include <string>
#include <variant>
#include <cassert>
int main(){
std::variant<std::string, int ,bool, long long int> value{"y"};
if(std::holds_alternative<std::string>(value)){
std::cout << "it's a std::string: " << std::get<std::string>(value) << std::endl;
}else if (value.index() == 0){
std::cout << "it's a string: " << std::get<std::string>(value) << std::endl;
}else if (value.index() == 1){
std::cout << "it's a int: " << std::get<int>(value) << std::endl;
}else if (value.index() == 2){
std::cout << "it's a bool: " << std::get<bool>(value) << std::endl;
}
}
预期是一个string类型,但实际它认为是bool类型, 编译执行:
改成:
// std::variant<std::string, int ,bool, long long int> value{"y"};
std::variant<std::string, int ,bool, long long int> value{std::string("y")};
就可以正常识别了:
这个问题在GCC7存在,但Clang不存在,是存在编译器差异的;需要明确的指明类型来防止这个错误,很容易忽视。
难道这是std::variant
遇到bool
类型有缺陷吗?实际上,这是一种普遍的隐式转换问题:
#include <iostream>
#include <string>
void foo(bool) {
std::cout << "bool\n";
}
void foo(std::string) {
std::cout << "string\n";
}
int main() {
foo("hello");
foo(std::string("hello"));
}
这个例子不管是GCC还是Clang都会认为是bool类型,找到一个解释如下:
The type of "hello" is const char [6], which decays to const char *. The conversion from const char * to bool is a built-in conversion, while the conversion from const char * to std::string is a user-defined conversion, which means the former is performed.
看起来这是历史包袱只能无可奈何了,除了明确写清楚类型之外,代替std::string
的还有另外一种方法,比如:
using namespace std::string_literals;
std::variant<std::string, int ,bool, long long int> value{"y"s};
后面加个s
就可以正常处理了,s
表示它是不会在\0
处截断的字符串,前提已经表明类型是字符串了。
总之,std::variant
中有bool
的时候,尤其string和bool同时出现时,警惕隐式转换。
参考¶
- https://mlog.club/article/179099
- https://github.com/pybind/pybind11/issues/1625
- https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0608r3.html
- https://www.appsloveworld.com/cplus/100/41/why-does-my-variant-convert-a-stdstring-to-a-bool
- https://en.cppreference.com/w/cpp/string/basic_string/operator%22%22s
- 微信搜索: 「 MinYiLife 」, 关注公众号!
- 本文链接: https://www.lesliezhu.com/blog/2022/11/16/cpp_go_to_wrong_1/
- 版权声明: 原创文章,如需转载请注明文章作者和出处。谢谢!