我有某种薛定谔变量
I have some kind of Schrödinger variable
我正在创建一个词法分析器,我需要计算一些东西。我创建了我的计算函数,它接受三个参数:两个字符串值和运算符。例如,当我执行 compute("34","63","+") 时,它 returns "94".
但是到了计算的时候,我首先必须将一些值转换为 int 或 float:
if(is_int(val1)){
int value1 = convert_to_int(val1);
}else if(is_float(val1)){
float value1 = convert_to_float(val1);
}else if(is_string(val1)){
string value1 = GetFrom(1,val1.size()-1,val1);
}else string value1 = val1;
if(is_int(val2)){
int value2 = convert_to_int(val2);
}else if(is_float(val2)){
float value1 = convert_to_float(val2);
}else if(is_string(val2)){
string value2 = GetFrom(1,val2.size()-1,val2);
}else string value2 = val2;
(opera代表运算符)
如果它既不是浮点数也不是整型数,它仍然是字符串。但是 g++ 不理解我使用变量的事实,他不知道它应该是什么。
我尝试在 (int value1; int value2;
) 之前声明变量,但是当我使用将字符串参数和伪整型变量作为参数的函数时,它不起作用。我也尝试使用 std::any 但无论如何。
所以我已经到了不得不问我的问题的地步:有没有办法告诉 g++ 不关心这个特定的错误?
您要找的是 variant
or a tagged union/algebraic sum type。
它有很多名字,但是“表示可以是 N 种类型中的一种的单个值”的模式在编程语言中很常见,并且通常被硬编码到变量中(Python,Ruby、Lisp、JavaScript 等)或通过显式 union/enum/sum 类型(C++、C、Rust、Java、C# 等)表示。
如果你会用C++17及以后的,你可以用std::variant<int, float, std::string>
随便用,然后用std::get<T>
,std::holds_alternative<T>
,[=15] =] 根据变体的类型进行一般查询、获取和执行操作。
如果 variant
值中包含相同的类型,下面的(非常粗略的初稿)代码应该可以工作,但在其他情况下仍然会失败。我还冒昧地为您使用但未定义的函数提供一些虚拟实现:
#include <variant>
#include <string>
#include <iostream>
#include <stdio.h>
using namespace std;
bool is_int(const string& s) {
try {
stoi(s);
return true;
} catch (invalid_argument e) {
return false;
}
};
bool is_float(const string& s){
try {
stof(s);
return true;
} catch (invalid_argument e) {
return false;
}
};
bool is_string(const string& s){
return true;
};
string GetFrom(size_t first_index, size_t last_index, const string& s){
return s.substr(first_index, last_index-first_index);
};
int convert_to_int(const string& s){
return stoi(s);
}
float convert_to_float(const string& s) {
return stof(s);
}
int main() {
variant<int, float, string> value1, value2;
string val1 = "123.43";
string val2 = "4566.123";
if (is_int(val1)) {
value1 = convert_to_int(val1);
} else if(is_float(val1)) {
value1 = convert_to_float(val1);
} else {
value1 = GetFrom(1,val1.size()-1,val1);
}
if (is_int(val2)) {
value2 = convert_to_int(val2);
} else if (is_float(val2)) {
value2 = convert_to_float(val2);
} else {
value2 = GetFrom(1,val2.size()-1,val2);
}
variant<int, float, string> result;
if (holds_alternative<int>(value1) && holds_alternative<int>(value2)) {
result = get<int>(value1) + get<int>(value2);
} else if (holds_alternative<float>(value1) && holds_alternative<float>(value2)) {
result = get<float>(value1) + get<float>(value2);
} else {
result = get<string>(value1) + get<string>(value2);
}
cout << holds_alternative<int>(value1) << endl;
visit([](const auto& val) {
cout << val << endl;
}, result);
return 0;
}
注意:您从字符串中检查变量类型的策略可能最好通过利用 regular expressions (regex), which are tailor-made and theoretically sound to perform the string-matching you desire. Most professional applications will use some sort of regex or context-free parsing algorithm 来解析简单类型的字符串或无限嵌套的字符串。
首先,我们定义 Value
可以保存带有类型标签的值:
using Value = std::variant<int, float, std::string>;
然后我们可以定义一个从操作数到值的函数:
Value from_string(std::string v) {
if (is_int(v))
return Value{std::in_place_type_t<int>{}, convert_to_int(v)};
if (is_float(v))
return Value{std::in_place_type_t<float>{}, convert_to_float(v)};
if (is_string(v))
return Value{GetFrom(1,v.size()-1,v)};
return Value{}; // TODO: handle this case.
}
并按如下方式实现加号运算符。如您所见,它非常冗长,因为它需要检查 3^2 种类型。
Value plus(const Value v1, const Value v2) {
if (auto v1_int = std::get_if<int>(v1)) {
if (auto v2_int = std::get_if<int>(v2))
return Value{std::in_place_type_t<int>{}, *v1_int + *v2_int};
if (auto v2_float = std::get_if<float>(v2))
return Value{std::in_place_type_t<float>{}, *v1_int + *v2_float};
if (auto v2_string = std::get_if<std::string>(v2))
return Value{std::to_string(*v1_int + *v2_string)};
} else
if (auto v1_float = std::get_if<float>(v1)) {
if (auto v2_int = std::get_if<int>(v2))
return Value{std::in_place_type_t<int>{}, *v1_float + *v2_int};
if (auto v2_float = std::get_if<float>(v2))
return Value{std::in_place_type_t<float>{}, *v1_float + *v2_float};
if (auto v2_string = std::get_if<std::string>(v2))
return Value{std::to_string(*v1_float + *v2_string)};
} else
if (auto v1_string = std::get_if<std::string>(v1)) {
if (auto v2_int = std::get_if<int>(v2))
return Value{*v1_string + std::to_string(*v2_int)};
if (auto v2_float = std::get_if<float>(v2))
return Value{*v1_string + std::to_string(*v2_float)};
if (auto v2_string = std::get_if<std::string>(v2))
return Value{*v1_string + *v2_string};
}
return Value{};
}
我正在创建一个词法分析器,我需要计算一些东西。我创建了我的计算函数,它接受三个参数:两个字符串值和运算符。例如,当我执行 compute("34","63","+") 时,它 returns "94".
但是到了计算的时候,我首先必须将一些值转换为 int 或 float:
if(is_int(val1)){
int value1 = convert_to_int(val1);
}else if(is_float(val1)){
float value1 = convert_to_float(val1);
}else if(is_string(val1)){
string value1 = GetFrom(1,val1.size()-1,val1);
}else string value1 = val1;
if(is_int(val2)){
int value2 = convert_to_int(val2);
}else if(is_float(val2)){
float value1 = convert_to_float(val2);
}else if(is_string(val2)){
string value2 = GetFrom(1,val2.size()-1,val2);
}else string value2 = val2;
(opera代表运算符)
如果它既不是浮点数也不是整型数,它仍然是字符串。但是 g++ 不理解我使用变量的事实,他不知道它应该是什么。
我尝试在 (int value1; int value2;
) 之前声明变量,但是当我使用将字符串参数和伪整型变量作为参数的函数时,它不起作用。我也尝试使用 std::any 但无论如何。
所以我已经到了不得不问我的问题的地步:有没有办法告诉 g++ 不关心这个特定的错误?
您要找的是 variant
or a tagged union/algebraic sum type。
它有很多名字,但是“表示可以是 N 种类型中的一种的单个值”的模式在编程语言中很常见,并且通常被硬编码到变量中(Python,Ruby、Lisp、JavaScript 等)或通过显式 union/enum/sum 类型(C++、C、Rust、Java、C# 等)表示。
如果你会用C++17及以后的,你可以用std::variant<int, float, std::string>
随便用,然后用std::get<T>
,std::holds_alternative<T>
,[=15] =] 根据变体的类型进行一般查询、获取和执行操作。
如果 variant
值中包含相同的类型,下面的(非常粗略的初稿)代码应该可以工作,但在其他情况下仍然会失败。我还冒昧地为您使用但未定义的函数提供一些虚拟实现:
#include <variant>
#include <string>
#include <iostream>
#include <stdio.h>
using namespace std;
bool is_int(const string& s) {
try {
stoi(s);
return true;
} catch (invalid_argument e) {
return false;
}
};
bool is_float(const string& s){
try {
stof(s);
return true;
} catch (invalid_argument e) {
return false;
}
};
bool is_string(const string& s){
return true;
};
string GetFrom(size_t first_index, size_t last_index, const string& s){
return s.substr(first_index, last_index-first_index);
};
int convert_to_int(const string& s){
return stoi(s);
}
float convert_to_float(const string& s) {
return stof(s);
}
int main() {
variant<int, float, string> value1, value2;
string val1 = "123.43";
string val2 = "4566.123";
if (is_int(val1)) {
value1 = convert_to_int(val1);
} else if(is_float(val1)) {
value1 = convert_to_float(val1);
} else {
value1 = GetFrom(1,val1.size()-1,val1);
}
if (is_int(val2)) {
value2 = convert_to_int(val2);
} else if (is_float(val2)) {
value2 = convert_to_float(val2);
} else {
value2 = GetFrom(1,val2.size()-1,val2);
}
variant<int, float, string> result;
if (holds_alternative<int>(value1) && holds_alternative<int>(value2)) {
result = get<int>(value1) + get<int>(value2);
} else if (holds_alternative<float>(value1) && holds_alternative<float>(value2)) {
result = get<float>(value1) + get<float>(value2);
} else {
result = get<string>(value1) + get<string>(value2);
}
cout << holds_alternative<int>(value1) << endl;
visit([](const auto& val) {
cout << val << endl;
}, result);
return 0;
}
注意:您从字符串中检查变量类型的策略可能最好通过利用 regular expressions (regex), which are tailor-made and theoretically sound to perform the string-matching you desire. Most professional applications will use some sort of regex or context-free parsing algorithm 来解析简单类型的字符串或无限嵌套的字符串。
首先,我们定义 Value
可以保存带有类型标签的值:
using Value = std::variant<int, float, std::string>;
然后我们可以定义一个从操作数到值的函数:
Value from_string(std::string v) {
if (is_int(v))
return Value{std::in_place_type_t<int>{}, convert_to_int(v)};
if (is_float(v))
return Value{std::in_place_type_t<float>{}, convert_to_float(v)};
if (is_string(v))
return Value{GetFrom(1,v.size()-1,v)};
return Value{}; // TODO: handle this case.
}
并按如下方式实现加号运算符。如您所见,它非常冗长,因为它需要检查 3^2 种类型。
Value plus(const Value v1, const Value v2) {
if (auto v1_int = std::get_if<int>(v1)) {
if (auto v2_int = std::get_if<int>(v2))
return Value{std::in_place_type_t<int>{}, *v1_int + *v2_int};
if (auto v2_float = std::get_if<float>(v2))
return Value{std::in_place_type_t<float>{}, *v1_int + *v2_float};
if (auto v2_string = std::get_if<std::string>(v2))
return Value{std::to_string(*v1_int + *v2_string)};
} else
if (auto v1_float = std::get_if<float>(v1)) {
if (auto v2_int = std::get_if<int>(v2))
return Value{std::in_place_type_t<int>{}, *v1_float + *v2_int};
if (auto v2_float = std::get_if<float>(v2))
return Value{std::in_place_type_t<float>{}, *v1_float + *v2_float};
if (auto v2_string = std::get_if<std::string>(v2))
return Value{std::to_string(*v1_float + *v2_string)};
} else
if (auto v1_string = std::get_if<std::string>(v1)) {
if (auto v2_int = std::get_if<int>(v2))
return Value{*v1_string + std::to_string(*v2_int)};
if (auto v2_float = std::get_if<float>(v2))
return Value{*v1_string + std::to_string(*v2_float)};
if (auto v2_string = std::get_if<std::string>(v2))
return Value{*v1_string + *v2_string};
}
return Value{};
}