0

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

我将如何解决这个问题?我的主要参考是这篇好文章,但我不能让它发挥作用。

好的,让我们深入了解:

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 回答 4

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();
}
于 2011-04-10T00:21:30.400 回答
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);
        });
    }
};
于 2011-04-10T13:27:15.697 回答
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...);
}

所以 &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);
   }
}

或使用绑定:

// 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);
于 2011-04-10T00:15:40.030 回答
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));
}

我希望可变参数模板解决方案能够以某种方式使客户端代码更简单,但现在我看不出它怎么能比这更简单。可变参数#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))。

于 2011-04-10T11:15:20.893 回答