Чтобы прокомментировать хороший ответ Говарда, позвольте мне заявить, что в конце я делаю вывод, что создание шаблонной функции 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)).