2

I posted this question. SpongeBobFan said the answer is reflection. I found Boost.Reflect and was wondering how the heck I can pull this off using that library or another C++ reflection library. Please explain your answer, as I cannot just glance at code and figure out what's going on. My question was this:

Ok, I have a question. Say I have this code:

int myfunc(int arg-a, int arg-b);
int mywrapperfunc(obj a, obj b);

mywrapperfunc is supposed to wrap myfunc. mywrapperfunc discards the first argument and takes the second, which is an array. I then uses the array items as parameters. But say I don't know how many parameters myfunc takes, nor do I know how many items are in the array-type object (b). How would I programatically call myfunc with the correct number of args? The number of args handed over would be the same as the number of items in the array-type object.

EDIT: arg-a and arg-b are supposed to come from the array-type object. I split the object into the args.

EDIT: Ok, ok, I'm trying to wrap the Python C API with some sense involved, hiding most background jobs.

Community
  • 1
  • 1
kirbyfan64sos
  • 9,193
  • 6
  • 51
  • 71

3 Answers3

3

Have you looked at Reflex? This tool uses GCC-XML to create a reflection library that is similar to the one in Java.

Here's my initial take on it (I currently don't have a lot of free time to flush it out further):

// Use the Reflex library to look up "myfunc" reflectively
Type t = Type::ByName("myfunc");
// The Reflex type 'Type" has a "FunctionParameterSize()" that tells
// you how many args in a function
size_t num_params = t.FunctionParameterSize();
// Use this information to call "myfunc" with objects from "b"

If Reflex only provides the invocation capability on a member of a class, then you could make myfunc() a static class member, and try something like this:

// Load MyClass reflectively (where MyClass contains a static member function "myfunc")
Type t = Type::ByName("MyClass");
// Find the member function "myfunc"
Member m = t.MemberByName("myfunc");
// Pack the parameters from "b" into a vector
// (Assumes "b" has indexing operators, and a "length()" function)
std::vector params(&b[0], &b[b.length()-1]);
// Invoke the method "myfunc" reflectively
m.Invoke(params);

You'll have to fiddle with this, I'm not sure if I'm doing the parameter passing correctly, etc. but hopefully this gives you some new ideas.

Tom
  • 2,281
  • 11
  • 20
  • How would I accomplish what I want using Reflex? – kirbyfan64sos Apr 16 '13 at 00:30
  • I edited the post with a very rough sketch of what I was thinking you could do with the Reflex library, but don't have time to work it out further. Have you looked at the documentation for the library, or downloaded it? – Tom Apr 17 '13 at 15:32
  • One more question: How would I call myfunc with correct args? – kirbyfan64sos Apr 17 '13 at 16:39
  • I think the Reflex library also has a way to `invoke()` a reflectively-loaded Type (kind of like Java), but I couldn't find the documentation for it. I found documentation for how to do it if `myfunc` were a member function of a class. I'll add more to my example. – Tom Apr 17 '13 at 16:47
  • One more question(again!): What if myfunc has an unlimited number of parameters? I have a hard time reading C++ documentation, since I got so used to the Python way of doing things. ARGHHH!!! Thanks for the help, though! – kirbyfan64sos Apr 17 '13 at 17:00
  • You have a function with an unlimited number of parameters? That might take a long time to run ;-) jk, I generalized the example a bit. – Tom Apr 17 '13 at 17:31
  • Thank you! I am writing a library, so a user might have unlimited arguments. When I make this library, your name will be on the "Thanks to" list. :) – kirbyfan64sos Apr 17 '13 at 17:40
2

The GCCXML/Reflex scheme suggested in a another answer essentially proposes that you run a step to preprocess your code, and extract information about the set of classes/functions/fields you have, so that you can programmatically access them. And given your stated that, that sounds like the right direction.

The Reflex scheme appears (I don't know anything about except what is posted in the other answer) to make this extra infromation available at runtime via a library that looks like dynamic reflection provided by other reflectable-languages, at the price of bloating the application with all this reflection data that you mostly don't use (the excuse for C++ was, "don't pay for what you don't use"). The point is you still have to write these psuedo-reflection calls to achieve your purpose, so you must know in advance to a great degree what you actually want to do.

You don't have to do it that way. If you have to preprocess the source code, you can get a preprocessor to extract the descriptive information (sort of like GCCXML), and simply generate calls on the targeted functions. The resulting program will do what the "reflection" one would do, but there's no runtime reflection library or bloat.

You can do this in theory with any program transformation. IN practice, such a tool must be able to process C++ and that's extremely hard.

There's only three tools on earth that can do this: our DMS Software Reengineering Toolkit with its C++ front end, Clang and (distant third) GCC.

All provide parsing of code, building ASTs and symbol tables (this is the reflection data you want), including all the microscopic details such as "number of arguments" (which appears to be a shortcoming of the Reflect scheme based on a comment in the other answer).

GCC can't regenerate valid C++ code although there is some extension called GCCMelt which makes some claim about this, that I have no experience with. (GCCXML is a custom hack of GCC to dump the symbol table data). Clang does provide the ability to modify C++ ASTs, but you have to hack at the trees through a procedural interface, which makes writing the transformations hard. DMS provides source-to-source surface syntax transformation capability, making it easier to write transformations. (YMMV).

The point is that by using such tools, you can write custom code to walk the symbol table to extract the function definitions etc. you want, and generate C++ code that does what you want (variable length argument lists and all). [This may be more complicated than you expect, but that's not different than the online reflection solution you already know about). No runtime reflection needed.

Don't expect any of these solutions to be easy to implement. C++ is a complicated language, and you'll pay the price for its complexity in whatever implementation scheme you choose, unless you are doing something really simple.

Steven Lu
  • 36,733
  • 50
  • 179
  • 328
Ira Baxter
  • 88,629
  • 18
  • 158
  • 311
  • 1
    Umm...this sounds more like an ad than an answer. Plus, I'm not rich. Anything that requires a quote is too expensive. – kirbyfan64sos May 14 '13 at 03:08
  • 1
    It offers you 3 solutions; agreed, I think ours is decent. All will be difficult, because C++ is difficult. Sounds like Clang is your best bet if you don't want to buy a commercial product. – Ira Baxter May 14 '13 at 03:50
  • Yeah, I already use Clang as my main C++ compiler, but both Clang and GCC started giving me linker issues, forcing me to resort to MSVC(ugh!). Is there a link thay shows a basic way to do this or describes it? And, I really can't afford commercial products unless they're $10. :) I wasn't trying to be mean by saying it sounds like an ad. You could just phrase it a but better so that the DMS doesn't overshadow everything else. I can see myself doing the same thing, though. – kirbyfan64sos May 14 '13 at 04:21
  • 1
    If you insist on sticking with MSVC, I don't believe there any solutions other than DMS. The open source community doesn't seem to have a lot of interest in supporting Microsoft's dialects. – Ira Baxter May 14 '13 at 19:42
  • I don't really like MSVC due to all the dependencies. Since I'm writing a library, I don't think DMS would quite work out, although I have to admit it looks interesting. Since I'm not building an EXE, Clang should work out fine. Could you post a link or something that talks about what you mentioned using Clang? Thanks for the help! And, I really don't like MSVC. The only reason I have it is that there are some Boost libraries that don't work with Clang or GCC on Windows. – kirbyfan64sos May 14 '13 at 20:04
  • 1
    I don't know of a lot of work with Clang in this area, and I don't have a lot of experience with it (you can guess I work with DMS daily). You can check out Eli Bendersky's discussions http://eli.thegreenplace.net/2012/06/08/basic-source-to-source-transformation-with-clang/ and http://clang-developers.42468.n3.nabble.com/AST-transformations-td2660810.html. – Ira Baxter May 14 '13 at 20:06
  • +1: Thank you! I'm still deciding between Reflex and Clang, largely because Reflex seems a heck of a lot easier. But Clang looks more capable. One more question: Is there something like a "personal" version of DMS? It is starting to look very interesting, especially with the Python front end. – kirbyfan64sos May 15 '13 at 03:15
  • No, as of this time there isn't a "personal" version. There are research versions; contact the company for details. – Ira Baxter May 15 '13 at 03:42
  • How much might it cost for one person? – kirbyfan64sos May 15 '13 at 03:47
  • Contact the company. Considerably more than $10.00, though. – Ira Baxter May 15 '13 at 04:23
  • Yeah, I guessed it would be more than $10! Thanks for the help! – kirbyfan64sos May 15 '13 at 04:42
1

Unfortunately, I don't think exactly what you want is feasible in C++. Since C++ code goes through 2 sequential stages, 1) Compilation and 2) Execution, you generally can't take something that is not known until execution time (the number of arguments needed by myfunc) and hand it back to the compiler so that the compiler can find the right myfunc to compile against.

Now, if myfunc() (which I assume is some Python C API call) is declared something like C's printf statement, you have some options. Printf in C is declared with a variable argument list, for example, stdio.h probably has a declaration similar to:

int printf ( const char * format, ... );

This allows printf to take any number of arguments. But from your description, that does not sound like the function (or set of functions?) that you want to wrap. Sometimes C++ template meta-programming techniques offer something close to what you want: if you can calculate the number of parameters at compile time, you can use a template class to choose the right prototype of myfunc to invoke. For example, maybe something like:

template<int N>
class Wrapper {
  public:
    mywrapperfunc() {
      if (N == 0) {
        // Call myfunc() with zero args here...
      } else if (N == 1) {
        // Call myfunc() with 1 arg here...
      } // etc...
    }
};

C++11 allows you some leeway in calculating the value of "N" to use at compile time via the constexpr keyword. But again, you must be able to know, or at least calculate, N at compile time for this to work.

Honestly, I can't think of any other way to make this work. Through many years of programming, I have come up with two basic rules that define this type of situation:

  1. If you have come up with a cool idea for a library, someone else has probably already written it, and it's probably better than your idea. Look harder.
  2. If nobody else has come up with that library yet, and you can't figure out (after a lot of research) how to do it, it probably can't be done with the technology that you're using (e.g.: C++).
Community
  • 1
  • 1
Ogre Psalm33
  • 19,630
  • 16
  • 73
  • 90
  • +1 I like your two rules at the end. But for novices it's always good to code it and *then* compare to what has been done by others. – Walter Apr 14 '13 at 17:07
  • @OgrePsalm33: Well, could I accomplish it using header-only library? – kirbyfan64sos Apr 14 '13 at 17:35
  • @OgrePsalm33: What about generating the variables in runtime? Also, are there any cross-platform languages that can accomplish this and can be used from C++? C++ could call it, and the other language does the actual work. – kirbyfan64sos Apr 14 '13 at 17:39
  • It *might* be possible using a header-only library, such as boost. I took a look at Boost Reflection, and it doesn't appear to be quite appropriate to this situation, although I could be wrong. Looking at this S.O. post: http://stackoverflow.com/questions/41453/how-can-i-add-reflection-to-a-c-application, this seems to apply to the top answer's "#1" category (can't be done :( ). As far as other languages, you might consider something like Jython, which I believe is Python running in a Java JVM (since you seem to be trying to interface to Python). But I haven't looked into it that much. – Ogre Psalm33 Apr 15 '13 at 12:48
  • @Walter Good point as far as a learning experience for novices. But ever since the Internet explosion of the mid-90's, I can't tell you how many times I've come up with a cool idea for a library, started coding it, and then mid-way through, while looking for some particular help online about coding it, actually found the entire library, already coded, and better than mine. – Ogre Psalm33 Apr 15 '13 at 13:20
  • @OgrePsalm33: I'm talking about Boost.Reflect at http://bytemaster.github.io/boost_reflect/index.html, not Boost.Reflection. – kirbyfan64sos Apr 16 '13 at 00:33
  • @kirbyfan64sos: I looked at that. This link: http://bytemaster.github.io/boost_reflect/group__boost__reflect__quickstart.html says there's 2 primary uses of the library: visiting members of a type, and type erasure. Type erasure won't help you. Visiting members of a type looks promising at first, but the implementation looks like it doesn't provide enough details to give you access to things like the number of arguments for a function. – Ogre Psalm33 Apr 16 '13 at 12:40