使用可变参数模板回调到模糊的重载

时间:2011-04-09 23:22:37

标签: templates c++11 bind variadic

在C ++ 0X中,我想使用可变参数模板编写通用调用者/回调函数。第一个障碍:被调用者是成员函数。到现在为止还挺好。第二个障碍:有许多同名的重载成员函数。

我该如何解决这个问题?我的主要参考是fine article,但我无法使其发挥作用。

好的,让我们潜入:

Class Foo
{
    void bar(int ID, int, int) { ... }
    void bar(int ID) { ... }
    void bar(int ID, double, float, void(Baz::*)()) const { /* jikes */ }

    template<typename ... Args>
    void sendBarToID_15(std::function<void(int, Args...)> refB, Args ... args)
    {
        refB(15, args...);
    }

    void yum()
    {
        sendBarToID_15(&Foo::bar, this, 17, 29); // want first version
    }
};

但是,我无法在yum()中编译调用,因为重载会阻止模板解析。根据引用的文章,我应该显式创建一个函数对象

f = magic::make_function<help, me>(&Foo::bar)

然后悠闲地致电sendBarToID_15(f, this, 17, 29)

  1. 我该如何做到这一点?

  2. std :: bind魔法的加分点在最后一行中避免使用“this”。

  3. 以有用的方式制作15个参数的额外奖励点。

  4. 很多谢谢!!

4 个答案:

答案 0 :(得分:2)

这是你要找的吗?

#include <functional>
#include <iostream>

class Baz;

class Foo
{
    void bar(int ID, int, int) { std::cout << "here\n"; }
    void bar(int ID) { /*...*/ }
    void bar(int ID, double, float, void(Baz::*)()) const { /* jikes */ }

    template<int ID, typename ... Args>
    void sendBarToID(std::function<void(int, Args...)> refB, Args&& ... args)
    {
        refB(ID, std::forward<Args>(args)...);
    }

public:
    void yum()
    {
        using namespace std::placeholders;
        void (Foo::*mfp)(int, int, int) = &Foo::bar;
        sendBarToID<15>(std::function<void(int, int, int)>
            (std::bind(mfp, this, _1, _2, _3)), 17, 29); // want first version
    }
};

int main()
{
    Foo foo;
    foo.yum();
}

答案 1 :(得分:1)

使用lambda函数 - 不再需要这种东西了。

class Foo
{
    void bar(int ID, int, int) { ... }
    void bar(int ID) { ... }
    void bar(int ID, double, float, void(Baz::*)()) const { /* jikes */ }

    template<typename ... Args>
    void sendBarToID_15(std::function<void(int, Args...)> refB, Args ... args)
    {
        refB(15, args...);
    }

    void yum()
    {
        sendBarToID_15([&, this](int i) {
            this->bar(i, 17, 29);
        });
    }
};

答案 2 :(得分:0)

您正尝试按顺序使用以下参数调用bar:15,this,17,29。

你想:这个,15,17,29

template<typename ... Args>
void sendBarToID_15(std::function<void(int, Args...)> refB, Args ... args)
{
    refB(15, args...);
}

所以&amp; Foo :: bar不能是std :: function

如果你可以使用lambda我会使用:

 void yum()
 {
    // EDITED: was "Foo* t"
    // (I don't remember of capture works with this, you may not need this)
    Foo* p = this;
    sendBarToID_15([p](int x, int y, int z){ p->bar(x, y, z); }, 17, 29);
 }

如果您无法使用帮助程序类实现它:

class helper {
private:
   Foo* p;
public:
   [...]
   void operator(int x, int y, int z) {
      p->bar(x,y,z);
   }
}

或使用bind:

// EDITED: wrong return type was used
void (Fred::*f)(char x, float y) = &Foo::bar;
sendBarToID_15(std::bind(f, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), 17, 29);

答案 3 :(得分:0)

为了跟进霍华德的好答案,让我先说明最后我得出结论,模板化sendBarToID函数并没有真正改善设置逻辑的方式。既然我们必须绑定(),那么没有理由首先绑定然后取消绑定占位符,我们也可以将所有内容绑定到位。这是非模板化版本:

void sendBarToID_15(std::function<void(int)> f)
{
    f(15);
}

void yum()
{
    // No avoiding this in the presence of overloads
    void (Foo::*mfp)(int, int, int) = &Foo::bar;

    sendBarToID_15(std::bind(mfp, this, std::placeholder::_1, 17, 29));
}

我希望可变参数模板解决方案能够以某种方式使客户端代码变得更简单,但现在我看不出它是如何比这更简单。 Variadic #define宏可以处理其余的事情。

感谢您的贡献!

更新好的,这就是我最终想出来的,感谢预处理器宏:

#include <functional>
#include <iostream>

class Baz;

class Foo
{
    void bar(int ID, const int &, int)
    { std::cout << "v1 called with ID " << ID << "\n"; }
    void bar(int ID)
    { std::cout << "v2 called with ID " << ID << "\n"; }
    void bar(int ID, double, float, void(Baz::*)()) const
    { std::cout << "v3 called with ID " << ID << "\n"; }

    void innocent(int ID, double)
    { std::cout << "innocent called with ID " << ID << "\n"; }

    void very_innocent(int ID, double) const
    { std::cout << "very innocent called with ID " << ID << "\n"; }

    template<int ID> void sendBarToID(std::function<void(int)> refB) { refB(ID); }
    template<int ID> void sendConstBarToID(std::function<void(int)> refB) const { refB(ID); }

#define MAKE_CALLBACK(f, ...) std::bind(&Foo::f, this, std::placeholders::_1, __VA_ARGS__)
#define MAKE_EXPLICIT_CALLBACK(g, ...) std::bind(g, this, std::placeholders::_1, __VA_ARGS__)

#define MAKE_SIGNED_CALLBACK(h, SIGNATURE, ...) MAKE_EXPLICIT_CALLBACK(static_cast<void (Foo::*)SIGNATURE>(&Foo::h), __VA_ARGS__)
#define MAKE_CONST_SIGNED_CALLBACK(h, SIGNATURE, ...) MAKE_EXPLICIT_CALLBACK(static_cast<void (Foo::*)SIGNATURE const>(&Foo::h), __VA_ARGS__)

public:
    void gobble()
    {
      double q = .5;
      int    n = 2875;
      void(Baz::*why)();

      sendBarToID<5>(MAKE_CALLBACK(innocent, q));
      sendConstBarToID<7>(MAKE_CALLBACK(very_innocent, q));
      // sendBarToID<11>(MAKE_SIGNED_CALLBACK(bar, (int))); // can't do, too much commas
      sendBarToID<13>(MAKE_SIGNED_CALLBACK(bar, (int, const int &, int), n, 1729));
      sendConstBarToID<17>(MAKE_CONST_SIGNED_CALLBACK(bar, (int, double, float, void(Baz::*)()), q, q, why));
    }

    void yum() const
    {
      double q = .5;
      int    n = 2875;
      void(Baz::*why)();

      sendConstBarToID<2>(MAKE_CALLBACK(very_innocent, q));
      // sendBarToID<-1>(MAKE_CALLBACK(innocent, q)); // Illegal in const function

      sendConstBarToID<3>(MAKE_CONST_SIGNED_CALLBACK(bar, (int, double, float, void(Baz::*)()), q, q, why));
    }
 };

int main()
{
    Foo foo;
    foo.yum();
    foo.gobble();
}

有一个不便之处:我需要为常量和非常量成员函数定义两个单独的函数和宏。另外,我无法处理空参数列表(Foo :: bar(int))。