ハワードのすばらしい答えをフォローアップするために、最後に、 sendBarToID 関数をテンプレート化しても、セットアップのロジックが期待どおりに改善されないという結論に達したことを述べさせてください。とにかく bind() しなければならないので、最初にプレースホルダーをバインドしてからアンバインドする理由はありません。テンプレートなしのバージョンは次のとおりです。
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();
}
不便な点が 1 つあります。定数メンバー関数と非定数メンバー関数に対して、2 つの別個の関数とマクロを定義する必要があります。また、空の引数リスト (Foo::bar(int)) を処理できません。