提问人:Armin Sobhani 提问时间:10/3/2023 最后编辑:Armin Sobhani 更新时间:10/5/2023 访问量:142
有没有办法访问存储在 C++ 中 std::bind() 返回的函数对象中的参数?
Is there a way to access arguments stored in the function object returned by std::bind() in C++?
问:
我需要一种方法来分解函数模板中返回的函数对象及其参数。std::bind()
下面的代码片段显示了我想做什么:
#include <iostream>
#include <functional>
void foo(int x, double y, char z)
{
std::cout << "x = " << x << ", y = " << y << ", z = " << z << '\n';
}
int main()
{
auto f = std::bind(foo, 42, 3.14, 'a');
std::cout << "The first argument is: " << std::get<0>(f) << '\n';
std::cout << "The second argument is: " << std::get<1>(f) << '\n';
std::cout << "The third argument is: " << std::get<2>(f) << '\n';
}
输出应为:
The first argument is: 42
The second argument is: 3.14
The third argument is: a
但它没有编译错误:
test.cpp:12:60: error: no matching function for call to ‘get<0>(std::_Bind<void (*(int, double, char))(int, double, char)>&)’
为什么我需要这个?
std::generate()
并且可以接受引擎或分布来生成随机数。当您传递分配时,除了函子和 lambda 之外,还有一种标准方法:std::generate_n()
std::bind
std::mt19937 R(666);
std::::uniform_int_distribution<int> D(0, 100);
std::vector<int> v(10);
std::generate(v.begin(), v.end(), std::bind(D, std::ref(R));
我开发了一种公平的并行算法(即,如果你使用相同的种子和分布,你总是得到相同的序列)。我希望它具有相同的接口,但该算法需要调用引擎的函数,这对于串行算法来说是不必要的。我的想法是用来查看是否传递了引擎或发行版。如果它是引擎,则调用,如果是绑定表达式,请先分解它,然后调用引擎。Lambda 在这里不起作用,因为算法无法访问引擎。
如果实现无法实现,那么我将实现我的 .generate()
std::generate()
discard()
std::is_bind_expression<T>::value
discard()
discard()
std::bind
std::bind
如果有更好的方法可以做到这一点,我会很高兴知道它。
答:
这是不可能的。
std::bind
返回一个未指定的类型,仅保证以下内容:
- 复制或移动构造函数;
- (已弃用)类型别名;
result_type
operator()
.
如果您需要问题中描述的功能,则必须提出自己的定义。bind
std::bind
可以被视为已弃用,并被 lambda 取代。我听说过仍然需要的案例,但我从未见过。std::bind
您可以编写自定义函数包装器,将参数存储在元组中。
#include <functional>
#include <tuple>
#include <iostream>
template <typename R,typename BoundTuple,typename ... Args>
struct my_function {
BoundTuple bound;
std::function<R(Args...)> func;
template <typename...MoreArgs>
R operator()(MoreArgs&& ... more) {
return std::apply(func,std::tuple_cat(bound,std::tuple(more...)));
}
};
template <typename R,typename ... Bound,typename ... Args>
my_function<R,std::tuple<Bound...>,Args...> my_bind(std::function<R(Args...)>&& f,Bound&&...b){
return {{b...},f};
}
void foo(int x, double y, char z) {
std::cout << "x = " << x << ", y = " << y << ", z = " << z << '\n';
}
int main()
{
auto f = my_bind(std::function(foo), 42, 3.14, 'a');
std::cout << "The first argument is: " << std::get<0>(f.bound) << '\n';
std::cout << "The second argument is: " << std::get<1>(f.bound) << '\n';
std::cout << "The third argument is: " << std::get<2>(f.bound) << '\n';
f();
}
但是,请对此持保留态度。不处理引用,只能绑定从左开始的参数。它只是为了说明这种方法。这种方法是否可以扩展到您的需求取决于细节。
以我的拙见,std::bind
的接口很糟糕(例如,“如果调用 g() 中提供的某些参数与存储在 g 中的任何占位符不匹配,则未使用的参数将被计算并丢弃。
评论
std::reference_wrapper
std::reference_wrapper
bind
std::thread
评论
std::bind
......” - 好吧,那么它就不再是一个发行版了。然后它只是一个普通的发电机。“to see if an engine or a distribution is passed” - 从不传递给 的发行版。为什么不为您的版本使用标准标签等?R()
generate
std::execution::par
generate