使用参数c ++ 11绑定泛型回调

时间:2017-01-06 13:12:08

标签: c++ c++11 generics callback

我有一个名为Renderer的类,它包含两个回调对象;

library(tidyr)
extract(df, text, into = c("first", "sec"), "(here)_(do)", remove = FALSE)
#  var_a var_b    text first  sec
#1     a    93 foo_bla  <NA> <NA>
#2     b    51 here_do  here   do
#3     c    65  oh_yes  <NA> <NA>
#4     d    70     baa  <NA> <NA>
#5     e    32    land  <NA> <NA>

我想有一个绑定这些回调的公共函数,它是模板化的,需要一个具有两个draw方法的类,每个方法都有它们的有效参数,如下所示:

void (*drawCall)(const sf::Drawable& drawable, const sf::RenderStates& states);
void (*drawPrimCall)(const sf::Vertex* vertices, unsigned int vertexCount,
    sf::PrimitiveType type, const sf::RenderStates& states);

然而,正如您可能想象的那样,这不起作用。我还在学习std :: bind,我不确定占位符的使用,我知道我在这里要做的是什么。

我已经尝试在Google上寻找答案但是有点令人生畏,感谢您的帮助!

更新:

好的,所以@Holt给出的答案有效,在更改为std :: function后,我的回调看起来像这样:

template<typename T>
inline void setRenderer(T* instance)
{
    using namespace std::placeholders;
    drawCall = std::bind(&T::draw, instance, _1, _2);
    drawPrimCall = std::bind(&T::draw, instance, _1, _2, _3, _4);
}

现在对于setRenderer方法由于外部库的约束,我还需要传递一个函数引用,就像这样;

std::function<void(const sf::Drawable& drawable, const sf::RenderStates& states)> drawCall_fn;
std::function<void(const sf::Vertex* vertices, unsigned int vertexCount,
                   sf::PrimitiveType type, const sf::RenderStates& states)> drawPrimCall_fn;

这样当我打电话时,我可以这样做:

template<typename T>
inline void setRenderer(T* instance, void(T::*drawCall)(const sf::Drawable&, const sf::RenderStates&))
{
    using namespace std::placeholders;
    drawCall_fn = std::bind(drawCall, instance, _1, _2);
}

**注意:我目前只处理drawCall_fn,因为我可以轻松扩展。

UPDATE2:为setRenderer drawCall添加了缺少的参数。

2 个答案:

答案 0 :(得分:2)

你无法使用函数指针做你想做的事情,因为你需要&#34;捕获&#34; (使用捕获lambda或使用std::bindinstance。您应该使用std::function

std::function<void(const sf::Drawable&, const sf::RenderStates&)> drawCall;
std::function<void(const sf::Vertex*, unsigned int,
    sf::PrimitiveType, const sf::RenderStates&)> drawPrimCall;

然后,您可以使用lambda或强制&T::draw的重载分辨率来分配它们:

drawCall = [instance](const sf::Drawable& drawable, const sf::RenderStates& states) {
    instance->draw(drawable, states);
});

// Or:
drawCall = std::bind((void (T::*)(const sf::Drawable&, const sf::RenderStates&))&T::draw, 
                     instance, _1, _2);

在这两种情况下,您都必须重新指定参数列表,但是您可以使用小辅助函数来避免这种情况:

template <typename T, typename R, typename... Args, typename... BArgs>
void gbind_mem(std::function<R(Args...)> &fn, R(T::*mfn)(Args...), 
               T *instance, BArgs&&... args) {
    fn = std::bind(mfn, instance, std::forward<BArgs>(args)...);
}

然后你可以使用:

轻松绑定
gbind_mem(drawCall, &T::draw, instance, _1, _2);

让编译器完成从drawCall推断参数的艰苦工作。

答案 1 :(得分:0)

  

...包含两个回调对象

在C ++中没有&#34;回调对象&#34; 这样的东西。您可能正在寻找的是function pointersstd::function。对于函数指针,您的语法不正确 - 您需要添加*

void (*drawCall)(const sf::Drawable& drawable, const sf::RenderStates& states = sf::RenderStates::Default);
void (*drawPrimCall)(const sf::Vertex* vertices, unsigned int vertexCount, sf::PrimitiveType type,
                    const sf::RenderStates& states = sf::RenderStates::Default);

然后您就可以设置它们了。例如:

void (*callback)(int); 
void real_function(int) { }

int main()
{
    callback = &real_function;
}

如果你的&#34;真正的功能&#34;签名与回调不匹配,你应该使用无法隐藏lambda expressions,它可以隐式转换为函数指针,以适应它:

void (*callback)(int); 
void real_function(int, float) { }

int main()
{
    callback = [](int x){ return real_function(x, 5.f); };
}

如果您在wandbox上提供最少示例,我将能够为您提供更具体的答案。