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);