lundi 24 août 2020

Is it possible to make a macro to reflect a C++ function declaration? And how?

I want to save and access at runtime the types and default values of inputs and outputs of a function.

I have some structs to hold what I need for now in FunDeclaration and FunParam and an example function foo to reflect. Live code here: https://onlinegdb.com/H10-Pq-7D

Here the full source:

#include <iostream>
#include <string>
#include <unordered_map>
#include <any>

struct FunParam {
    // This will be a custom identifier (string for now) "int", "string", etc...
    std::string type;
    // Default value for that parameter
    std::any default_value;
};

struct FunDeclaration {
    // Function input params 
    std::unordered_map<std::string, FunParam> ins;
    // Function output params
    std::unordered_map<std::string, FunParam> outs;
};

using FunctionsMap = std::unordered_map<std::string, FunDeclaration>;

void print(FunctionsMap &fmap) {
    auto printParam = [](FunParam& p) {
        if (p.type == "int") {
            std::cout << "type: " << p.type << " default_value: " << std::any_cast<int>(p.default_value);
        } else if (p.type == "double") {
            std::cout << "type: " << p.type << " default_value: " << std::any_cast<double>(p.default_value);
        } else if (p.type == "float") {
            std::cout << "type: " << p.type << " default_value: " << std::any_cast<float>(p.default_value);
        } else if (p.type == "std::string") {
            std::cout << "type: " << p.type << " default_value: " << std::any_cast<std::string>(p.default_value);
        }
    };

    for (auto& f : fmap) {
        std::cout << "Fun: " << f.first << std::endl;
        for (auto& in: f.second.ins) {
            std::cout << "\t[in] name: " << in.first << " ";
            printParam(in.second);
            std::cout << std::endl;
        }

        for (auto& f : fmap) {
            for (auto& in : f.second.outs) {
                std::cout << "\t[out] name: " << in.first << " ";
                printParam(in.second);
                std::cout << std::endl;
            }
        }
    }
}



// Just an example function to work with, multiple inputs (default values), and multiple outputs
std::tuple<double, float> foo(int a = 10, std::string b = "HelloWorld") {
    return { a * 10.0, b.size() };
}

int main() {
    FunctionsMap gFuns;
    gFuns["foo"].ins = 
        { 
            {"a", {"int", std::any(int(10))} },
            {"b", {"std::string", std::any(std::string("HelloWorld"))} }
        };

    gFuns["foo"].outs = {
        {"out0", {"double", std::any(double())} },
        {"out1", {"float", std::any(float())} }
    };
    
    print(gFuns);
    return 1;
}

How would you define a macro that spits this glue code(suppose gFuns is a global), and with multiple inputs/outputs? Is this possible with just one macro? Or I have to make a macro to each possibility of in/out param numbers?

    gFuns["foo"].ins = 
        { 
            {"a", {"int", std::any(int(10))} },
            {"b", {"std::string", std::any(std::string("HelloWorld"))} }
        };

    gFuns["foo"].outs = {
        {"out0", {"double", std::any(double())} },
        {"out1", {"float", std::any(float())} }
    };

I was thinking about something like this:

#define ADD_FUN_DECL(name, in_types, in_defaultvalues, out_types, out_defaultvalues)





Aucun commentaire:

Enregistrer un commentaire