Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
622 views
in Technique[技术] by (71.8m points)

c++ - How to do a runtime subclassing system

I am doing a subclassing system which may be defined in runtime. I have a subclass that forwards the method for a table (std::map), if a method is not available in the table, the super class method is used.

Example (function parameters and return type are not the problem, I just simplified it):

class Superclass {
public:
    virtual void doSomething();
};

class Superclass_subclass : public Superclass {
public:
    std::map< std::string,std::function<void (Superclass_subclass*)> > table;

    int doSomething(int a, int b) {
        if( table.count("doSomething") == 0 ) return Superclass::doSomething(a,b);
        return table.at("doSomething")(this,a,b);
    }
};

Now I am working on macros to ease the process of creating the _subclass classes. Right now I got the following macros:

#define runtime_subclass_begin(Superclass) //...
#define runtime_subclass_method(Superclass,rtype,method,args_def,args_call) //...
#define runtime_subclass_end
#define GROUP(...) __VA_ARGS__


runtime_subclass_begin(Superclass)
runtime_subclass_method(Superclass,int,doSomething,GROUP(int a,int b),GROUP(a,b))
runtime_subclass_end

It is working well for me, except that I have to repeat the arguments, once with the types(int a, int b), and once for calling the underlying function(a,b). I was wondering if there is a better way to do that.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

If what you want is to remove the redundancy of the parameter names in the declaration (appearing once in the declaration list with their types, and once in the call list just as names), you can do this by supplying the names and the types as two separate lists, and just zipping them together with an appropriate two-parameter map macro.

Assuming the above is accurate, it looks like the actual parameter names aren't too important either, so you can lighten up your declaration further by predefining a list of dummy names, and leaving it out of the visible part of the declaration:

#define NARGS(...) NARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define NARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N

#define CAT(A, B) CAT_(A, B)
#define CAT_(A, B) A##B
#define ID(...) __VA_ARGS__
#define APPEND(L, E) ID(L),E
#define FIRST(A, ...) A
#define REST(A, ...) __VA_ARGS__

#define ZIP(F, L1, L2) CAT(ZIP_, ID(NARGS L1))(F, L1, L2)

#define ZIP_4(F, L1, L2) F(ID(FIRST L1), ID(FIRST L2)), ZIP_3(F, (ID(REST L1)), (ID(REST L2)))
#define ZIP_3(F, L1, L2) F(ID(FIRST L1), ID(FIRST L2)), ZIP_2(F, (ID(REST L1)), (ID(REST L2)))
#define ZIP_2(F, L1, L2) F(ID(FIRST L1), ID(FIRST L2)), ZIP_1(F, (ID(REST L1)), (ID(REST L2)))
#define ZIP_1(F, L1, L2) F(ID(FIRST L1), ID(FIRST L2))
#define ZIP_0(F, L1, L2)


#define GENSYMS (_0, _1, _2, _3, _4, _5, _6, _7, _8, _9)

#define runtime_subclass_method(Superclass,rtype,method,args) 
    rtype method(ZIP(EMIT_DECL, args, GENSYMS)) { 
        if( table.count(#method) == 0 ) return Superclass::method(ZIP(EMIT_CALL, args, GENSYMS)); 
        return table.at(#method)(this, ID(ZIP(EMIT_CALL, args, GENSYMS))); 
    }
#define EMIT_DECL(T, N) T N
#define EMIT_CALL(T, N) N


runtime_subclass_method(Superclass,int,doSomething,(int,int))

Most of this example is utility stuff (such as CAT). Expanding ZIP, NARGS and GENSYMS to accept more arguments (four is a little small to be practical) should be trivial.

The method declaration just accepts a list of argument types, zips them together with names from a predefined list for the declaration, and just zips the length with the names to generate a call list.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...