C++代码优化求助:宏粘贴错误及JSON类型检查代码简化
Hey there, let's fix that repetitive JSON type checking code and resolve the macro preprocessing error you're hitting. Here's how to approach this:
Why Your Macro Failed
The error "pasting "<" and "string" does not give a valid preprocessing token" happens because the C++ preprocessor treats < as a separate operator token, and string as an identifier. Trying to splice them together with ## doesn't work—preprocessor tokens can't be formed by combining these distinct elements that way.
Better Option: Use a Template Function (Type-Safe & Clean)
Instead of relying on macros (which are error-prone and lack type safety), a template function is the idiomatic C++ way to eliminate repetitive code. Here's how to implement it:
#include <nlohmann/json.hpp> // Adjust based on your JSON library using json = nlohmann::json; // Assume YourResultType is the type of your _result variable template<typename T> bool validate_json_field(const json& incoming_json, const std::string& field_name, YourResultType& result) { if (incoming_json.contains(field_name) && incoming_json[field_name].is<T>()) { __TRACE("argument type OK\n"); return true; } else { __ERROR("invalid type for field: " << field_name << "\n"); result.rc = ERROR_CODE_INVALID_TYPE; // Add your _req_ error handling logic here (e.g., setting error messages) return false; } }
How to Use It
Now you can replace all those duplicate code blocks with a single function call for each field type:
// Check for a string field if (!validate_json_field<std::string>(json_data_incomming, "value", _result)) { // Exit early or handle error return; } // Check for an integer field if (!validate_json_field<int>(json_data_incomming, "count", _result)) { return; } // Works with any type your JSON library supports (e.g., bool, double) if (!validate_json_field<bool>(json_data_incomming, "is_active", _result)) { return; }
This approach is:
- Type-safe: The compiler will catch invalid type arguments at compile time.
- Maintainable: If you need to adjust the error logic, you only change it once in the template function.
- Readable: The function name makes it clear what's happening, unlike opaque macros.
If You Must Use a Macro (Not Recommended)
If you have a specific reason to stick with macros, you can avoid the token-pasting issue by passing the full type as a parameter instead of trying to splice it. Here's a working macro:
#define CHECK_JSON_FIELD(json_obj, field, type, result) \ do { \ if ((json_obj).contains(field) && (json_obj)[field].is<type>()) { \ __TRACE("argument type OK\n"); \ } else { \ __ERROR("invalid type for field: " field "\n"); \ (result).rc = ERROR_CODE_INVALID_TYPE; \ // Add your _req_ error handling here \ } \ } while(0)
Usage Example
CHECK_JSON_FIELD(json_data_incomming, "value", std::string, _result); CHECK_JSON_FIELD(json_data_incomming, "age", int, _result);
The do { ... } while(0) wrapper ensures the macro behaves like a single statement, preventing issues with if/else blocks without braces.
内容的提问来源于stack exchange,提问作者Martin Borůšek

