Non-type template parameter... that's a template! (C++)
Asked Answered
Z

4

6

I'm basically looking to generate a wrapper for a generic C function without having to manually specify the types. So I have a callback with a fixed prototype but I'm going to need to do some special code in the wrapper based on the type of the wrapped function... So basically I'm thinking about using a static method in a class template to wrap my function to a conforming interface e.g.:

// this is what we want the wrapped function to look like
typedef void (*callback)(int); 
void foobar( float x ); // wrappee

// doesn't compile
template< T (*f)(S) > // non-type template param, it's a function ptr
struct Wrapper
{
  static void wrapped(int x)
  {
     // do a bunch of other stuff here
     f(static_cast<S>(x)); // call wrapped function, ignore result

  }
}

And then I'd like to do something like:

AddCallback( Wrapper<foobar>::wrapped );

However, the problem is that I can't just go ahead and use a "S" in the parameter of the function in the Wrapper template, I have to first list it as a parameter:

template< class T, class S, T (*f)(S) >
struct Wrapper
// ...

But this means it's a lot more painful to use (Wrapper<void,float,foobar>::wrapped), ideally I'd like to just pass in the function pointer there and have it work out the types of the parameters (and return types) automatically. To be clear, inside the wrapped function I'm going to need to refer to the types of the function pointer (so I do need some equivalent of S or T).

Is there a way of doing this?

Zooid answered 15/7, 2009 at 18:17 Comment(1)
@damndirtyape: I've thought about your question, and I think I've done something similar. Unfortunately it involved a lot of code. Basically, my solution had a base class which overloaded operator() and I had factory functions which constructed base classes of that based on the function type passed. If you like I can post the code in a pastebin somewhere.Abulia
S
5

One thing you might wish to consider is using LLVM or similar to generate an appropriate trampoline function at runtime. Or here's a static solution:

#include <iostream>

void f(float f) { std::cout << f << std::endl; }

template<typename T, typename S> struct static_function_adapter {
        template<T(*f)(S)> struct adapt_container {
                static void callback(int v) {
                        f(static_cast<S>(v));
                }
        };

        template<T(*f)(S)> adapt_container<f> adapt() const {
                return adapt_container<f>();
        }
};

template<typename T, typename S> struct static_function_adapter<T, S> get_adapter(T (*)(S)) {
        return static_function_adapter<T, S>();
}

#define ADAPTED_FUNCTION(f) (&get_adapter(f).adapt<f>().callback)

int main() {
        void (*adapted)(int) = ADAPTED_FUNCTION(f);
        adapted(42);
        return 0;
}

The get_adapter function allows us to infer the argument and return type; adapt() then converts this into a type parameterized on the actual function, and finally we get a static function in callback.

Spontaneity answered 15/7, 2009 at 19:6 Comment(1)
I have just no idea about what this code is supposed to do and what problem it is supposed to solve :OPrimer
G
0

If you use a function that returns the "wrapped" rather than referring to it directly, the compiler will attempt to automatically match the template parameters for the function call.

edit: What about this?

int foobar( float x ); // wrappee

template <typename T, typename S>
struct Wrapper {
    typedef T (*F)(S);
    F f;

    Wrapper(F f) : f(f) { }

    void wrapped(S x) {
        // do a bunch of other stuff here
        f(x); // call wrapped function, ignore result
    }
};

template <typename T, typename S>
Wrapper<T,S> getWrapper(T (*f)(S)) {
    return Wrapper<T,S>(f);
}

...
getWrapper(foobar).wrapped(7);
Girth answered 15/7, 2009 at 18:24 Comment(3)
That doesn't solve the problem, because now the template parameters to that function has the same issue.Zooid
Doesn't work because you changed the function from being a static method to being an instance method, but the whole point was to make the wrapped function conform to an existing callback signature (which means it must be static).Zooid
Ah, I see what you mean. Yeah... I don't see a good, simple way to do that. I'll have to think about it.Girth
A
0

EDIT: completely new answer

OK, I've completely re-thought the question and believe that I get what you want. I've actually done this before :-P.

Here's the idea, I have a Base class which overloads operator(), then I have a subclass for each "arity" of functions. Finally I have a factory function which will return one of these things. The code is big (and probably a little overkill) but works nicely. Much of the library_function overloads are to support different syntaxes, mostly unnecessary. It also supports boost::bind functions, member functions, etc, very much more than you probably need.

http://pastebin.com/m35af190

Example, usage:

// map of library functions which will return an int.
std::map<std::string, LibraryFunction<int> > functions;

// function to register stuff in the map
void registerFunction(const std::string &name, LibraryFunction<int> func) {
    functions.insert(std::make_pair(name, func));
}

later you can do this:

// the this param is so the function has access to the scripting engine and can pop off the parameters, you can easily chop it out

// register 2 functions, one with no params, one with 1 param
registerFunction("my_function", library_function1(*this, call_my_function));
registerFunction("my_function2", library_function0(*this, call_my_function2));

functions["my_function"]();
functions["my_function2"]();
Abulia answered 15/7, 2009 at 18:28 Comment(3)
This doesn't let me wrap an existing function, I have to write a new object which means I still have to specify the types up front rather than having them inferred?Zooid
I don't see how that helps me. Basically I have a specific callback signature (which I have no control over), I need to wrap a large number of existing C functions to conform to this callback signature (it's a script binding thing, so for a 3 parameter function I need to pop 3 values off the stack, pass them to the wrappee, and push the result back on to the stack - but externally every single function has the exact same signature).Zooid
Again, that doesn't help me. I need to turn it into a function pointer that's compatible with a fixed callback signature. This doesn't do that. I need to turn a function that takes a string (say) to a function that corresponds to the callback, by doing some magic (pushing the string to a stack etc.) inside the function, but the signature of this wrapped function must correspond to the callback.Zooid
B
0

I'd look at boost. At first reading of your question, it seems to me than <boost/function_types/parameter_types.hpp> provides what your need.

Balky answered 15/7, 2009 at 18:37 Comment(4)
Not a really good answer: without at least pointing to the concerned boost library, it's like saying "Search on Google, I think the answer lies there". Moreover, I don't see anything in Boost that can fulfill the OP requirements. Could you be more specific in your answer?Taynatayra
I had. I had used directly &lt; et &gt; instead of HTML entities and the header name was hidden. I've edited my answer to correct that.Balky
An in comments, one doesn't need the entities and < and > works... well, I'm still learning the interface.Balky
Regarding < >, another good solution is to put the concerned text into backquotes; this way, the text is formatted as code.Taynatayra

© 2022 - 2024 — McMap. All rights reserved.