Упрощение использования std :: function, хранящейся в члене класса std :: vector - PullRequest
0 голосов
/ 29 декабря 2018

Я написал этот базовый класс для хранения std::function<T> в std::vector<T>, и у меня есть два бесплатных шаблона функций foo() и bar(), которые оба возвращают void и принимают std::vector<T> в качестве параметра.В настоящее время они делают то же самое для простоты;но допустим, что в будущем они будут выполнять различные вычисления или задачи.Пока что это то, что я придумал:

#include <vector>
#include <functional
#include <iostream>
#include <exception>

template<typename T>
class MyClass {
private:
    std::vector<std::function<void(std::vector<T>)>> myFuncs_;    
public:
    MyClass() = default;

    void addFunc( std::function<void(std::vector<T>)> func ) {
        myFuncs_.push_back(func);
    }

    std::function<void(std::vector<T>)> caller(unsigned idx) {
        return myFuncs_.at(idx);
    }
};

template<typename T>
void foo(std::vector<T> data) {
    std::cout << "foo() called:\n";

    for (auto& d : data) 
        std::cout << d << " ";
    std::cout << '\n';
}

template<typename T>
void bar(std::vector<T> data) {
    std::cout << "bar() called:\n";

    for (auto& d : data)
        std::cout << d << " ";
    std::cout << '\n';
} 

int main() {
    try {
        MyClass<int> myClass;
        std::vector<int> a{ 1,3,5,7,9 };
        std::vector<int> b{ 2,4,6,8,10 };

        std::function<void(std::vector<int>)> funcA = std::bind(foo<int>, a);
        std::function<void(std::vector<int>)> funcB = std::bind(bar<int>, b);
        myClass.addFunc( funcA );
        myClass.addFunc( funcB );

        myClass.caller(0)(a);
        myClass.caller(1)(b);       

    } catch( std::runtime_error& e ) {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;    
}  

И это достаточно уверенные выводы:

foo() called:
1 3 5 7 9
bar() called:
2 4 6 8 10

Вот что я хотел бы знать: есть или естьЕсть ли способ (ы), чтобы упростить этот код;например, некоторые синтаксисы выглядят излишними: в основной функции после того, как я создал экземпляр шаблона моего класса и создал std::vector со значениями, я создаю экземпляр std::function<T>, используя std::bind с функцией Iхочу затем добавить в вектор моего класса.Затем, связав их и добавив их в контейнер моего класса, я вызываю функцию класса для индексации функции, которую хочу вызвать, используя std::functions 's operator().Однако функция ожидает std::vector<T>, поэтому кажется, что я передаю это vector<T> несколько раз, как вы можете видеть из этой части из моего кода выше.

// std::vector<T> being passed to std::bind
std::function<void(std::vector<int>)> funcA = std::bind(foo<int>,a);
myClass.addFunc( funcA );
myClass.caller(0)(a);  // Again std::vector<T> being passed but to `std::function`'s operator because the stored function requires this parameter. 

Можно ли это упростить или этопросто в семантике как работают std::function и std::bind?Если это можно упростить, будет ли это сделано внутри самого класса, чтобы облегчить его для пользователя, или это будет со стороны пользователя?

1 Ответ

0 голосов
/ 29 декабря 2018

Вы используете std::bind неверным образом, например, в

std::function<void(std::vector<int>)> funcA = std::bind(foo<int>, a);

Вы уже связали аргумент a с foo<int>, что означает, что любой параметр, который вы передадите funcA не вступит в силу, приведенное выше эквивалентно

std::function<void()> funcA = std::bind(foo<int>, a);

Для простоты кода, если вы хотите придерживаться std::bind, вы можете просто использовать оператор вызова на MyClass, который вызываетвсе зарегистрированные std::function:

template<typename T>
class MyClass {
private:
    std::vector<std::function<void()>> myFuncs_;
public:
    MyClass() = default;

    template <class... F, std::enable_if_t<(sizeof...(F) > 0), bool> = true>
    void addFunc(F&&... func) {
        ((myFuncs_.push_back(std::forward<F>(func))), ...);
    }

    void operator()() const {
        for (auto& fn : myFuncs_) {
            fn();
        }
    }
};


auto funcA = std::bind(foo<int>, a);
auto funcB = std::bind(bar<int>, b);
myClass.addFunc(funcA, funcB);
myClass();

, используя эту же идею, вы можете в любое время переключиться на лямбды вместо.

...