简体   繁体   English

非类型模板参数......这是一个模板! (C ++)

[英]Non-type template parameter… that's a template! (C++)

I'm basically looking to generate a wrapper for a generic C function without having to manually specify the types. 我基本上希望为通用C函数生成包装器,而无需手动指定类型。 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 eg: 所以我有一个带有固定原型的回调,但是我需要根据包装函数的类型在包装器中做一些特殊的代码...所以基本上我在考虑在类模板中使用静态方法将我的函数包装到一致的接口,例如:

// 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: 但是,问题是我不能继续在Wrapper模板中的函数参数中使用“S”,我必须先将其列为参数:

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. 但这意味着使用它会更加痛苦( Wrapper<void,float,foobar>::wrapped ),理想情况下我只想传递函数指针并让它计算出参数的类型(并返回)类型)自动。 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). 要清楚,在包装函数内部我需要引用函数指针的类型(所以我需要一些等价的S或T)。

Is there a way of doing this? 有办法做到这一点吗?

One thing you might wish to consider is using LLVM or similar to generate an appropriate trampoline function at runtime. 您可能希望考虑的一件事是使用LLVM或类似的方法在运行时生成适当的trampoline函数。 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; get_adapter函数允许我们推断参数和返回类型; adapt() then converts this into a type parameterized on the actual function, and finally we get a static function in callback. adapt()然后将其转换为在实际函数上参数化的类型,最后我们在回调中获得静态函数。

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);

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. 我之前实际上已经这样做了:-P。

Here's the idea, I have a Base class which overloads operator(), then I have a subclass for each "arity" of functions. 这是一个想法,我有一个重载operator()的Base类,然后我为每个“arity”函数都有一个子类。 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. 很多library_function重载都支持不同的语法,大多数都是不必要的。 It also supports boost::bind functions, member functions, etc, very much more than you probably need. 它还支持boost::bind函数,成员函数等,远远超出您的需要。

http://pastebin.com/m35af190 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"]();

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. 在您第一次阅读您的问题时,在我看来, <boost/function_types/parameter_types.hpp>提供了您的需求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM