I am using macros to determine a variable's real type based on a pattern, and I am getting some weird macro errors that I do not understand:
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.
Why is this happening? I have no idea, please provide some help if you know why.
#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
As I understood the motivation of the OP's question the intention is:
Types of variables have to be defined at compile time. (That's one of the C++ language core concepts called static type checking. There is no chance to define a type of a variable at runtime.)
So, all the types which shall be supported have to defined in the source code at the same time.
As an input term may always have at most one of these types, the storage of the values may consider that.
In C, a union would come in mind but C++ provides something even better: std::variant.
The variant will be defined with all supported types but an instance will always store a value of one of them. The type is chosen in the assignment depending of the right hand side.
An example to demonstrate that in action:
#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';
}
}
Output:
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'