6

I've written a very basic expression parser and I would like it to be extendable so it can parse user defined expression types. For exemple, if when parsing I meet the character <, I want to create an instance of the class used to parse expressions starting by this character.

I have two questions:

  1. How can I associate a character to a static method pointer?

    I want to use a static method that will return a new instance of the class since I can't get a pointer to the class constructror. The following syntax is probably wrong, but that's the idea:

    typedef static IValue * (*returnPtrIValue)();
    map<char, returnPtrIValue> ...
    
  2. Assuming I have class A, and class B extends class A, can I initialize a pointer to a function returning a pointer/ref to a A with a pointer to a function returning a pointer/ref to a B since a B is an A?

    For example, can I do:

    typedef A * (*returnPtrA)();
    B * func() { ... }
    returnPtrA foo = func;
    
3
  • Parsing is done by a class method/function which is shared across all the objects, then why do you want to create a new instance of a class every time? Just store a global object of the class associated with < and use its method. Commented May 26, 2013 at 11:29
  • Because in the way i designed my parser, an expression is an object which parses itself out of a piece of string. Commented May 26, 2013 at 11:30
  • if you are interested in writing a parsing/lexer I suggest to take a look at libclang, for example stackoverflow.com/questions/14509120/any-tutorial-on-libclang Commented May 26, 2013 at 14:15

5 Answers 5

3

1: Remove static from your typedef, like:

typedef IValue * (*returnPtrIValue)();

Pointer to static member function can be then assigned to the variable (or be put into map) of that type , like:

returnPtrIValue fun = &SomeClass::somestaticfun;

Is this what you are asking for?

2: Generally speaking - no. Not in typesafe way, at least. Covariance does not work in C++ that way.

If you really want to do this you can do this is with either reinterpret_cast or doing some hackery with unions, but this may be compiler-dependant and I wouldn't recommend that (I can give you some hints if you do want this anyway).

UPDATE: Here is the really good article, that explains how to implement delegates in C++ with help of (member) function pointers in C++. It delves pretty deeply into the question and I've found that the first half of it is pretty good reference/explanation of (member) function pointers in C++ and how to work with them. I suggest to check it out if you're interested in understanding how they work in C++.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, for 1 yes that's what i needed, and for the 2 i'll see if there is another way.
@Virus721 Cool, comment here if you'll need tips on 2. Also check out update on my post - might become handy to you.
Thanks but i found what i needed here : stackoverflow.com/questions/4007382/… :D
2

1) Just remove static from your typedef, a "static method" is like a simple function (only declared inside the scope of a class).

2) That seemed legit but unfortunately I get a compiler error:

error: invalid conversion from 'B* (*)()' to 'A* (*)()'

It seems that function pointers don't support covariant return types...

1 Comment

Thanks, i'll see if i can do it in another way.
1

If you're using C++11, you can try something like this:

#include <map>
#include <functional>
...
std::map<char, std::function<parser*()>> m;
m['a'] = []{return new parser_for_a;};

This way you don't need to have any static methods.

2 Comments

Thanks, seems elegant, but i'm gonna use this on mobile devices using visual studio 2005 and i'm not sure it handles C++11 stuff.
Yeah, you'll need vs2010 at the very least.
0

This code should answer your questions, even if not exactly. In fact, I solved some of your issues by using virtual calls (beware: performance issues).

#include <iostream>
#include <map>


struct parse_result {
    // something here
};

class parser {
public:
    virtual parse_result parse() = 0;
};

class parser1 : public parser {
public:
    parse_result parse() {
        // something here
        std::cout << "Called parser1::parse()" << std::endl;
        return parse_result();
    }
};

class parser2 : public parser {
public:
    parse_result parse() {
        // something here
        std::cout << "Called parser2::parse()" << std::endl;
        return parse_result();
    }
};

static parser1* make_parser1() {
    return new parser1();
}

static parser2* make_parser2() {
    return new parser2();
}

typedef parser* (*parser_factory_method)();


int main() {

    std::map<char, parser_factory_method> parsers;
    parsers.insert(std::make_pair('1', (parser_factory_method) make_parser1));
    parsers.insert(std::make_pair('2', (parser_factory_method) make_parser2));

    for (auto entry : parsers) {
        std::cout << "Calling parser for " << entry.first << std::endl;
        parser_factory_method pfm = entry.second;
        parser* p = pfm();
        p->parse(); // parse_result is ignored here, but can be used as needed
        delete p;
    }

    return 0;

}

Please note that I don't like this design for a parser. It mimics Java reflection somehow and it is doomed to have performance issues. See if you can refine it.

2 Comments

Thanks, i'll see if i can adapt this to what i'm doing.
Please note it uses some non-vital C++11 functionalities. It can be conveniently downgraded.
0

This thread helped me doing what i wanted : How to create class objects dynamically? Thanks for your answers !

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.