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;
    
Mat
  • 202,337
  • 40
  • 393
  • 406
Virus721
  • 8,061
  • 12
  • 67
  • 123
  • 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. – iammilind May 26 '13 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. – Virus721 May 26 '13 at 11:30
  • if you are interested in writing a parsing/lexer I suggest to take a look at `libclang`, for example http://stackoverflow.com/questions/14509120/any-tutorial-on-libclang – user2384250 May 26 '13 at 14:15

5 Answers5

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++.

Eugene Loy
  • 12,224
  • 8
  • 53
  • 79
  • Thanks, for 1 yes that's what i needed, and for the 2 i'll see if there is another way. – Virus721 May 26 '13 at 11:58
  • @Virus721 Cool, comment here if you'll need tips on 2. Also check out update on my post - might become handy to you. – Eugene Loy May 26 '13 at 12:45
  • Thanks but i found what i needed here : http://stackoverflow.com/questions/4007382/how-to-create-class-objects-dynamically :D – Virus721 May 26 '13 at 14:32
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...

gx_
  • 4,690
  • 24
  • 31
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.

catscradle
  • 1,709
  • 11
  • 18
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.

gd1
  • 11,300
  • 7
  • 49
  • 88
0

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

Community
  • 1
  • 1
Virus721
  • 8,061
  • 12
  • 67
  • 123