Как мне написать функцию-оболочку с параметрами шаблонной функции, которая может принимать перегруженные функции-члены? - PullRequest
1 голос
/ 06 мая 2019

Я работаю с устаревшей кодовой базой, которая использует несколько обратных вызовов для функций-членов. В рамках процесса рефакторинга я пытаюсь обернуть эти обратные вызовы.

Моя текущая реализация пытается использовать функцию шаблона переменной для замены / переноса вызова связывания.

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, если это имеет значение.

1 Ответ

0 голосов
/ 07 мая 2019

вы можете попытаться принудительно указать тип ожидаемой функции-члена:

#include <iostream>
#include <boost/bind.hpp> // Boost 1.53

template<typename T, typename... Args>
auto
my_bind(void (T::*fxn)(Args...), 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";
    }
};

int main() {

    Klass k;

    auto f1a = my_bind( &Klass::foo, &k, 2 );
    f1a(); // prints One param: 2
    auto f2a = my_bind( &Klass::foo, &k, 2, 3 );
    f2a(); // prints Two param: 2 3

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...