简化存储在类的 std::vector 成员中的 std::函数的使用

Simplifying the use of std::function stored within a class's std::vector member

本文关键字:std 函数 成员 vector 存储      更新时间:2023-10-16

我已经编写了这个基类来将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::bind创建了std::function<T>的一个例子,然后我想将该函数添加到类的向量中。然后,在绑定它们并将它们添加到类的容器中之后,我在这里调用类的函数,以使用std::functionsoperator()对要调用的函数进行索引。然而,函数需要一个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::functionstd::bind如何工作的语义?如果这可以简化,是在类本身中进行,以使用户更容易,还是从用户端进行?

您使用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();

使用同样的想法,您可以随时切换到lambdas。