我有某种薛定谔变量

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{};
}