使用可变参数模板回调不明确的重载 [英] Callback with variadic template to ambiguous overloads

查看:254
本文介绍了使用可变参数模板回调不明确的重载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我如何解决这个问题?我的主要参考资料是此精致文章,但我不能



好的,让我们来看看:

 类Foo 
{
void bar(int ID,int,int){...}
void bar(int ID){...}
void bar ,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 ,17,29)


  1. 如何使这项工作?

    / li>
  2. std :: bind魔法的奖励点,在最后一行中消除this。



很多感谢!

$ b $为了跟进Howard的正确答案,让我只是说,最后我的结论是,使sendBarToID函数模板化并不真正改善的逻辑。设置在我希望的方式。因为我们必须绑定()无论如何,没有理由先绑定,然后解除绑定占位符,我们可能只是绑定一切就位。这里是非模板版本:

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

void yum()
{
//不存在重载时避免这种情况
void(Foo :: * mfp)(int ,int,int)=& Foo:bar;

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


$ b $ p我希望可变模板解决方案能够使客户端代码更简单,但现在我不知道如何可以得到任何比这更简单。



更新



非常感谢您的支持。 :好的,这是我终于想到的,感谢预处理程序宏:

  #include& 
#include< iostream>

class Baz;

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

void innocent(int ID,double)
{std :: cout< 无罪调用ID<< ID<< \\\
; }

void very_innocent(int ID,double)const
{std :: cout< 非常无辜的用ID< ID<< \\\
; }

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 :: placeholder :: _ 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))); //不能,太多的逗号
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)); //非法的const函数

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


In C++0X, I want to write generic caller/callback functions using variadic templates. First hurdle: The callees are member functions. So far so good. Second hurdle: There are many overloaded member functions of the same name.

How would I solve this? My primary reference is this fine article, but I can't quite make it work.

OK, let's dive in:

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

However, I cannot compile the call in yum() because the overload prevents template resolution. According to the referenced article, I should explicitly create a function object

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

and then leisurely call sendBarToID_15(f, this, 17, 29).

  1. How can I make this work?

  2. Bonus points for std::bind magic that obviates "this" in the last line.

  3. Extra bonus points for making 15 parametric in a useful way.

Lots of thanks!!

解决方案

To follow up Howard's fine answer, let me just state that in the end I conclude that making the sendBarToID function templated doesn't really improve the logic of the setup in the way I had hoped. Since we have to bind() anyway, there's no reason to first bind and then unbind placeholders, we might as well just bind everything right in place. Here's the non-templated version:

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

I was hoping that the variadic template solution could somehow make the client code simpler, but now I don't see how it can get any simpler than this. Variadic #define macros take care of the rest.

Thank you for the contributions!

Update: OK, here's what I finally came up with, thanks to preprocessor macros:

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

There is one inconvenience: I need to define two separate functions and macros for constant and non-constant member functions. Also, I can't handle the empty argument list (Foo::bar(int)).

这篇关于使用可变参数模板回调不明确的重载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆