Я работаю с устаревшей кодовой базой, которая использует несколько обратных вызовов для функций-членов. В рамках процесса рефакторинга я пытаюсь обернуть эти обратные вызовы.
Моя текущая реализация пытается использовать функцию шаблона переменной для замены / переноса вызова связывания.
template< typename F, typename T, typename... Args >
auto
my_bind(F fxn, T * obj, Args&&... args)
-> decltype( boost::bind( fxn, obj, std::forward<Args>(args)... ) )
{
return boost::bind( fxn, obj, std::forward<Args>(args)... );
}
(Реальная реализация добавит классы-оболочки вокруг объектов fxn & obj, но я удалил это, чтобы дать минимальный пример, который все еще показывает проблему.)
Это в основном работает, но не работает, когда объект fxn является перегруженной функцией-членом. В этой ситуации я получаю сообщение «Не могу вывести параметр шаблона« F »» / «Не могу определить аргумент шаблона« F »» (GCC / Clang). Это имеет смысл, так как есть несколько возможных функций с различными типами параметров, которые можно использовать.
Что меня смущает, так это то, что boost :: bind не имеет проблем с разрешением элемента - в исходном коде без оболочки я не вижу никаких ошибок, и привязка проходит хорошо. Пример:
#include <iostream>
#include <boost/bind.hpp> // Boost 1.53
template< typename F, typename T, typename... Args >
auto
my_bind(F fxn, T * obj, Args&&... args)
-> decltype( boost::bind( fxn, obj, std::forward<Args>(args)... ) )
{
return boost::bind( fxn, obj, std::forward<Args>(args)... );
}
class Klass {
public:
void foo( int i ) {
std::cout << "One param: " << i << "\n";
}
void foo( int i, int j ) {
std::cout << "Two param: " << i << " " << j << "\n";
}
void bar( int const & i ) const {
std::cout << "Bar One param: " << i << "\n";
}
int bar( float i, int j ) {
std::cout << "Bar Two param: " << i << " " << j << "\n";
return j;
}
};
int main() {
Klass k;
auto f1 = boost::bind( &Klass::foo, &k, 1 );
f1(); // prints "One param: 1"
auto f2 = boost::bind( &Klass::foo, &k, 1, 2 );
f2(); // prints "Two param: 1 2"
//auto f1a = my_bind( &Klass::foo, &k, 1 ); // Compiler error: couldn't deduce template parameter ‘F’
//auto f2a = my_bind( &Klass::foo, &k, 1, 2 ); // Compiler error: couldn't deduce template parameter ‘F’
double a = 1.1;
int b = 3;
//auto b1 = my_bind( &Klass::bar, &k, b ); // Should also work with const functions and const parameters
//auto b2 = my_bind( &Klass::bar, &k, a, 2 ); // As well as non-void return types and parameter conversions
// As well as any other member function which the underlying sub-function (here boost::bind) can take.
return 0;
}
Мой главный вопрос: Учитывая функцию (например, но не обязательно ограниченную boost::bind
), которая способна надлежащим образом различать различные версии перегруженной функции-члена, существует ли способ создания шаблонной оболочки функция, которая может «идеально пересылать» тип шаблона из этого параметра функции, то есть есть ли способ, позволяющий компилятору делать вывод типа F
на основе (рабочего) вывода типа подфункции (например, * * 1016) 1018 **
(Я попытался заменить шаблонную функцию my_bind на переменный макрос препроцессора. Это решает непосредственную проблему, но приводит к проблемам позже, когда я пытаюсь обернуть объект fxn
в шаблонный тип. - Я получаю аналогичное ошибки «не удается устранить перегруженную функцию».)
Я нацеливаюсь на C ++ 11, если это имеет значение.