C++ std::function与std::bind配合使用效果很好,但为什么呢?

C++ std::function与std::bind配合使用效果很好,但为什么呢?,c++,c++11,c++17,std-function,stdbind,C++,C++11,C++17,Std Function,Stdbind,我使用的是std::uniform\u int\u分布来生成素数(p)。我将分发对象放在匿名命名空间中,这看起来像是C++的“静态链接”,用于成年人……/P> namespace { // a more pedantic range: [2, 18446744073709551557] std::uniform_int_distribution<uint64_t> p_dist {2}; std::mt19937 rng; // (sufficient IV

我使用的是
std::uniform\u int\u分布
来生成素数
(p)
。我将分发对象放在匿名命名空间中,这看起来像是C++的“静态链接”,用于成年人……/P>
namespace
{
    // a more pedantic range: [2, 18446744073709551557]
    std::uniform_int_distribution<uint64_t> p_dist {2};

    std::mt19937 rng; // (sufficient IV states for uniqueness)
}
这非常方便,因为我有一个确定性的
u64\u素数(p)
函数,使用它可以确定
(p)
是否为素数:

uint64_t p;
while (!u64_prime(p = p_dist(rng)))
    ;
现在我创建一个
std::function
对象:

std::function<uint64_t()> zp_rng = std::bind(
    decltype(p_dist){0, p - 1}, std::ref(rng));
std::function zp\u rng=std::bind(
decltype(p_dist){0,p-1},std::ref(rng));
此函数:
zp\u rng()
可被调用以返回
Z(p)
中的随机数。也就是说,从引用的rng的结果中为:
[0,p-1]
使用分布对象


现在这是非常令人印象深刻的-但我通过剪切和粘贴有效地采用了它,而对
std::function
之间的交互以及
std::bind
参数之间的交互知之甚少

我没有被
decltype(p_dist){0,p-1}
搞糊涂——这只是一种指定我们仍然希望使用
std::uniform_int_分布的方法。我对
std::ref(rng)
的理解是,它阻止实例化rng的本地副本,并强制使用引用来代替。。。因此:


Q:有效确定使用的基本规则是什么:
dist(rng)
-我不明白为什么
std::bind
会强制执行这种交互。许多交互似乎基于
操作符()
方法

Q
std::function
在上被称为“通用多态函数包装器”。那么,它是封装
uint64\t
返回类型的函数吗?还是再次使用
操作符()
语法来驱动函数的概念

尽管这些构造非常有用,但我觉得我在某种程度上是在进行货运邪教编程。我正在寻找一个答案,以具体的方式解决任何歧义,并为类似的问题增加洞察力——
bind
参数预期如何交互,以及
函数
签名如何反映这一点



对于使用
std::bind
,我没有得到任何积极的反馈。即使在如此简单的情况下,简单地使用lambda函数也会带来很多优越的结果(和代码生成)。我自己的测试验证了这一点。

std::bind
有点与
std::function
无关,它所做的只是包装一些可调用的东西,以便始终传递一组特定的参数,请参阅

std::function
只接受任何适合指定为其模板参数的函数签名的可调用内容

std::uniform\u int\u distribution
可调用,因为它指定了
运算符()
,请参阅。这就需要一台发电机。我们使用bind来围绕它创建一个包装器,这样就不必总是显式地传递生成器。然后,结果存储在
std::function
中,该函数与uint64\t返回类型匹配,并且没有参数(因为生成器参数已绑定)


如果这个概念与您无关,您应该阅读运算符重载,参见(具体函数调用操作符)。

< P> >在现代C++中不需要使用<代码> STD::BIN < /C> > -使用lambda代替:

// NOTE: p and rng are captured by reference and must outlive zp_rng!
std::function<uint64_t()> zp_rng = [&]() { return decltype(p_dist){0, p - 1}(rng); };
//注意:p和rng是通过引用捕获的,必须比zp\u rng更长寿!
函数zp_rng=[&](){返回decltype(p_dist){0,p-1}(rng);};
至于和实例,它们是可调用的函数对象,也就是说,它们有我引用的
操作符()
什么是
bind()

函数适配器将函数作为参数并返回函数 对象,该对象可用于调用原始函数。标准 库提供了用于执行参数的
bind()
mem\u fn()
适配器 绑定,也称为Currying或部分求值。活页夹是 在过去大量使用,但大多数使用似乎更容易 使用lambdas表示

double cube(double);
auto cube2 = bind(cube,2);
调用
cube2()
将使用参数
2
调用
cube
,即,
cube(2)

可以直接使用
bind()
,它可以用来初始化 自动变量。因此,
bind()
类似于lambda

如果我们想将
bind()
的结果赋给带有 特定类型,我们可以使用标准库类型
函数
。A.
函数
使用特定的返回类型和特定的 参数类型

标准库
函数
是一种可以容纳任何对象的类型 可以使用调用运算符
()
调用。即,类型为的对象
函数
是一个
函数对象

所以
std::function
是一个函数对象。函数对象用于定义可以像函数一样调用的对象。 这是函数对象的一个示例:

template<typename T>
class Cube2 {
const T val; // value to compare against
public:
Cube2 (const T& v) :val(v) { }
double operator()(const T& x) const { return pow(x,3); } // call operator
};
模板
类立方2{
const T val;//要比较的值
公众:
立方2(常数T&v):val(v){}
双运算符()(const T&x)const{return pow(x,3);}//调用运算符
};

auto-cube2=bind(立方体,2)
就像说
cube2cube2{2}

Q:有效确定使用的基本规则是什么:dist(rng)——我不明白为什么std::bind会强制执行这种交互。许多交互似乎都基于操作符()方法

std::bind
执行。第一个参数必须是函数对象,即类似于函数的对象(例如,普通函数,或具有重载的
运算符()
)的类)

调用
std::bind
会复制其参数“bin”
template<typename T>
class Cube2 {
const T val; // value to compare against
public:
Cube2 (const T& v) :val(v) { }
double operator()(const T& x) const { return pow(x,3); } // call operator
};
int f(int i) { return i; }
auto f1 = std::bind(f, 1);
auto f1 = std::bind(f, 1);
std::function<int()> f1 = std::bind(f, 1);