类似于函数的宏不接受嵌套的#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,但是C ++提供了更好的东西: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