1

So, to start, I'm hesitant to ask this because there is (basically) the same question regarding this on SO, but the answers didn't fix my problem.

Question I've checked: C++ map<char, static method pointer>? (Marked as duplicate of How to create class objects dynamically? but I'm not dynamically creating objects)

I'm working on a PEG parser (cpp-peglib), and would like to map a string (token rule name) to a static function (the parser function).

For those not familiar, cpp-peglib takes actions as lambdas, in the form of [](const SemanticValues& vs) {}.

So I have a structure containing static methods that are my parser actions, looking something like this:

struct T {
    static auto getParser_A() {
        return [](const SemanticValues& vs) {/* return parsed token*/};
    }
    static auto getParser_B() {
        return [](const SemanticValues& vs) {/* return parsed token*/};
    }
};

I'd like to map the actions to the names of the rules, something like:

std::map<std::string,/* static method reference */> actionMap

So that I can add my rules like:

parser[RULE_NAME] = actionMap[RULE_NAME];

I have tried this:

map<string,function<T*>> mapping;

And this:

typedef T* (*action)();
map<string,action> mapping;

but I get could not convert ‘{{"A", T::getParser_A}, {"B", T::getParser_B}}’ from ‘’ to ‘std::map, std::function >’ for both versions.

What am I doing wrong? And how would store a static method returning a lambda in a map?

Werlious
  • 583
  • 6
  • 15
  • `T::getParser_A` You want to get the return value or you want to use the function? Also, why `return [](){ ... }`? Why not just make an actual function `static auto parse_b(const SemanticValues& vs) { ... }`? | "could not convert ‘{{"A", T::getParser_A}, {"B", T::getParser_B}}" - please post an [MCVE] to reproduce the error. You said you want `parser[RULE_NAME] = actionMap[RULE_NAME];`. Where do you use `{{ "A",....` syntax? Please post the code. What type does the lambda return? – KamilCuk Aug 01 '21 at 15:53
  • 2
    Do all getParser_X have same return type? Why is return type a T*? – Sreeraj Chundayil Aug 01 '21 at 15:57
  • @KamilCuk Sorry, I didn't include the entire code because of its heavy dependence on cpp-peglib. I'd like to get the return value of `T::getParser_A`, which would be the lambda function passed to cpp-peglib. And unfortunately, I've tried passing static functions to the parser and it does not like it (the compiler I mean). And I have `{{"A",T::getParser_A},...}` being the initialization of the map. As for the lambda return value, cpp-peglib specifies that the return value is wrapped in `any` – Werlious Aug 05 '21 at 15:36
  • @InQusitive Yes, all the getParser variants share a return type, namely `any` as required by cpp-peglib. As @KamilCuk pointed out, my example code is lacking detail. I was stuck between storing the static function and the lambda (return value of the function) itself (neither was working), so for the question `T*` was a pointer to T, the struct in my example – Werlious Aug 05 '21 at 15:40

2 Answers2

1

getParser_A returns a lambda, like a pointer to a function. So a pointer to getPArser_A is a pointer to a function that returns a function. You can store that in a map. I am assuming below the functions returns an int.

#include <map>
#include <vector>
#include <functional>
#include <string>

struct SemanticValues {};
struct T {
    static auto getParser_A() {
        return [](const SemanticValues& vs) {
            return 1;
        };
    }
    static auto getParser_B() {
        return [](const SemanticValues& vs) {
            return 2;
        };
    }
};

int main() {
    std::map<std::string, 
         // Function that returns a function that returns an int and takes SemanticValues
         std::function<std::function<int (const SemanticValues& vs)> ()> > m;
    m["A"] = T::getParser_A;
    m["B"] = T::getParser_B;
}
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • How do I call m["A"]? m["A"]()()? – Sreeraj Chundayil Aug 01 '21 at 16:14
  • `SemanticValues something; ["A"]()(something)` – KamilCuk Aug 01 '21 at 16:28
  • This is good, but is there any way I can initialize this in place? I probably should have put more detail in the question, but all this is going to be header only and I'd really rather prefer the map be const but I've already had issues with other const members – Werlious Aug 02 '21 at 01:19
  • Also, as per cpp-peglib's docs, `A semantic action can return a value of arbitrary data type, which will be wrapped by peg::any. If a user returns nothing in a semantic action, the first semantic value in the const SemanticValues& vs argument will be returned. `. peg::any is basically a typedef of std::any, so technically will be returning `any` – Werlious Aug 02 '21 at 01:22
-1

The syntax for an std::function from a value of type const SemanticValues& to type T* is

std::function<T*(const SemanticValues&)>`

This type can be assigned any lambda, functor, or function pointer whose argument and result types are correct.

Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116