类似函数的宏不接受嵌套#define

Function-like macro not accepting nested #define

我正在使用宏来根据模式确定变量的真实类型,但我遇到了一些我不理解的奇怪的宏错误:

a.cpp:15:4: error: '#' is not followed by a macro parameter
                #define USING_INTEGER\
                 ^
a.cpp:15:11: error: unknown type name 'USING_INTEGER'
                #define USING_INTEGER\
                        ^
a.cpp:16:2: error: expected unqualified-id
        else if (matchRegex(DOUBLE_REGEX, val))\
        ^
3 errors generated.

为什么会这样?不懂,有知道的请帮忙

#include "example_3.cpp"
#include <regex>

std::string INT_REGEX = "^[-+]?\d+$",
            DOUBLE_REGEX = "^[-+]?\d+\.\d?$",
            BOOLEAN_REGEX = "^(true|false)$";

bool matchRegex(std::string pattern, std::string inputString) {
    std::regex expression(pattern);
    return std::regex_match(inputString, expression);
}

#define determineType(var)\
    if (matchRegex(INT_REGEX, val))\
        #define USING_INTEGER\
    else if (matchRegex(DOUBLE_REGEX, val))\
        #define USING_DOUBLE\
    else if (matchRegex(BOOLEAN_REGEX, val))\
        #define USING_BOOL\
    else\
        #define USING_RAW

据我了解,OP 问题的动机是:

  • 解析文本
  • 确定某种类型的输入
  • 以该类型存储值。

必须在编译时定义变量类型。 (这是称为 static type checking 的 C++ 语言核心概念之一。 没有机会在运行时定义变量的类型。)

因此,必须同时在源代码中定义所有应支持的类型。

由于输入项可能总是最多具有这些类型中的一种,因此值的存储可能会考虑这一点。

在 C 中,union would come in mind but C++ provides something even better: std::variant.

变体将使用所有支持的类型进行定义,但实例将始终存储其中一种类型的值。根据右侧的作业选择类型。

演示实际操作的示例:

#include <iostream>
#include <sstream>
#include <string>
#include <variant>

// an error type
struct None { std::string text; };

// a value what can represent one of all supported types
typedef std::variant<bool, int, double, std::string, None> Value;

// reads a value from a text determining its type
Value readInput(const std::string &text)
{
  // check for int
  { std::istringstream in(text); int value;
    if (in >> value && in.tellg() == -1) {
      return Value(value);
    }
  }
  // check for floating point
  { std::istringstream in(text); double value;
    if (in >> value && in.tellg() == -1) {
      return Value(value);
    }
  }
  // check for bool
  if (text == "true") return Value(true);
  if (text == "false") return Value(false);
  // check for (quoted) string
  if (text.size() >= 2
    && ((text.front() == '"' && text.back() == '"')
    || (text.front() == '\'' && text.back() == '\''))) {
    return Value(text.substr(1, text.size() - 2));
  }
  // ERROR
  return Value(None{ text });
}

// prints the value (considering the current type)
void print(const Value &value)
{
  switch (value.index()) {
    case 0: std::cout << "bool: " << std::boolalpha << std::get<bool>(value); break;
    case 1: std::cout << "int: " << std::get<int>(value); break;
    case 2: std::cout << "double: " << std::get<double>(value); break;
    case 3: std::cout << "string: '" << std::get<std::string>(value) << '\''; break;
    case 4: std::cout << "ERROR! text: '" << std::get<None>(value).text << '\''; break;
    default: std::cout << "Value not initialized.";
  }
}

int main()
{
  const std::string tests[] = {
    "true", // bool
    "false", // bool
    "123", // int
    "123.17", // double
    "0", // int
    "0.0", // double
    "'text'", // string
    "''", // string
    "something that doesn't match any type" // ERROR
  };
  for (const std::string &test : tests) {
    std::cout << "Test \"" << test << "\"\n";
    const Value value = readInput(test);
    std::cout << "Got: ";
    print(value);
    std::cout << '\n';
  }
}

输出:

Test "true"
Got: bool: true
Test "false"
Got: bool: false
Test "123"
Got: int: 123
Test "123.17"
Got: double: 123.17
Test "0"
Got: int: 0
Test "0.0"
Got: double: 0
Test "'text'"
Got: string: 'text'
Test "''"
Got: string: ''
Test "something that doesn't match any type"
Got: ERROR! text: 'something that doesn't match any type'

Live Demo on coliru