【问题标题】:Non-type template parameter... that's a template! (C++)非类型模板参数...这是一个模板! (C++)
【发布时间】:2009-07-15 18:17:20
【问题描述】:

我基本上希望为通用 C 函数生成一个包装器,而无需手动指定类型。所以我有一个带有固定原型的回调,但我需要根据包装函数的类型在包装器中执行一些特殊代码......所以基本上我正在考虑在类模板中使用静态方法将我的函数包装到一个符合要求的接口,例如:

// 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

  }
}

然后我想做类似的事情:

AddCallback( Wrapper<foobar>::wrapped );

但是,问题是我不能直接在 Wrapper 模板中的函数参数中使用“S”,我必须先将其列为参数:

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

但这意味着使用起来会更加痛苦(Wrapper&lt;void,float,foobar&gt;::wrapped),理想情况下,我只想在那里传入函数指针并让它自动计算出参数的类型(和返回类型)。需要明确的是,在包装函数内部,我需要引用函数指针的类型(所以我确实需要一些等价的 S 或 T)。

有没有办法做到这一点?

【问题讨论】:

  • @damndirtyape:我考虑过你的问题,我想我也做过类似的事情。不幸的是,它涉及大量代码。基本上,我的解决方案有一个重载 operator() 的基类,并且我有工厂函数,它根据传递的函数类型构造基类。如果您愿意,我可以将代码发布到某个地方的 pastebin 中。

标签: c++ templates marshalling wrapper


【解决方案1】:

您可能希望考虑的一件事是使用 LLVM 或类似方法在运行时生成适当的蹦床函数。或者这是一个静态解决方案:

#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;
}

get_adapter 函数允许我们推断参数和返回类型; adapt() 然后将其转换为实际函数上参数化的类型,最后我们在回调中得到一个静态函数。

【讨论】:

  • 我只是不知道这段代码应该做什么以及应该解决什么问题:O
【解决方案2】:

如果您使用返回“包装”而不是直接引用它的函数,编译器将尝试自动匹配函数调用的模板参数。

编辑:这个呢?

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

【讨论】:

  • 这并不能解决问题,因为现在该函数的模板参数也有同样的问题。
  • 不起作用,因为您将函数从静态方法更改为实例方法,但重点是使包装的函数符合现有的回调签名(这意味着它必须是静态)。
  • 啊,我明白你的意思了。是的...我没有看到一个好的,简单的方法来做到这一点。我得考虑一下。
【解决方案3】:

编辑:全新的答案

好的,我已经完全重新考虑了这个问题,并相信我能得到你想要的。我之前实际上已经这样做了:-P。

这就是想法,我有一个重载 operator() 的基类,然后我为每个“arity”函数都有一个子类。最后我有一个工厂函数,它将返回其中之一。代码很大(可能有点矫枉过正),但运行良好。大部分library_function 重载是为了支持不同的语法,大部分是不必要的。它还支持boost::bind 函数、成员函数等,远远超出您的需要。

http://pastebin.com/m35af190

示例、用法:

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

稍后你可以这样做:

// 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"]();

【讨论】:

  • 这不允许我包装现有函数,我必须编写一个新对象,这意味着我仍然必须预先指定类型而不是推断它们?
  • 我看不出这对我有什么帮助。基本上我有一个特定的回调签名(我无法控制),我需要包装大量现有的 C 函数以符合这个回调签名(这是一个脚本绑定的东西,所以对于一个 3 参数函数我需要弹出从堆栈中取出 3 个值,将它们传递给 wrappee,然后将结果推回堆栈 - 但在外部,每个函数都具有完全相同的签名)。
  • 再一次,这对我没有帮助。我需要把它变成一个与固定回调签名兼容的函数指针。这不这样做。我需要通过在函数内部做一些魔术(将字符串推送到堆栈等),将一个接受字符串(比如说)的函数转换为对应于回调的函数,但是这个包装函数的签名 必须对应回调。
【解决方案4】:

我会看看提升。初读您的问题,在我看来,&lt;boost/function_types/parameter_types.hpp&gt; 提供了您的需求。

【讨论】:

  • 不是一个很好的答案:至少没有指向相关的 boost 库,就像说“在 Google 上搜索,我认为答案就在那里”。此外,我在 Boost 中看不到任何可以满足 OP 要求的东西。您能否更具体地回答?
  • 我有。我直接用过 <等>而不是 HTML 实体,并且标题名称被隐藏。我已经编辑了我的答案来纠正这个问题。
  • 在 cmets 中,一个不需要实体,并且 可以工作......好吧,我还在学习界面。
  • 关于,另一个很好的解决方案是将相关文本放在反引号中;这样,文本被格式化为代码。
猜你喜欢
  • 2014-10-03
  • 2021-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-06
相关资源
最近更新 更多