在研究这个问题时,我注意到GCC(V4.7)的std::function
实现在取值时移动了参数。下面的代码显示了此行为:
#include <functional>
#include <iostream>
struct CopyableMovable
{
CopyableMovable() { std::cout << "default" << '\n'; }
CopyableMovable(CopyableMovable const &) { std::cout << "copy" << '\n'; }
CopyableMovable(CopyableMovable &&) { std::cout << "move" << '\n'; }
};
void foo(CopyableMovable cm)
{ }
int main()
{
typedef std::function<void(CopyableMovable)> byValue;
byValue fooByValue = foo;
CopyableMovable cm;
fooByValue(cm);
}
// outputs: default copy move move
在这里,我们看到执行了cm
的一个副本(这似乎是合理的,因为byvalue
的参数是由value取的),但接下来有两个移动。由于function
是在cm
的副本上操作的,因此它移动参数的事实可以看作是一个不重要的实现细节。但是,当将function
与bind
一起使用时,此行为会引起一些麻烦:
#include <functional>
#include <iostream>
struct MoveTracker
{
bool hasBeenMovedFrom;
MoveTracker()
: hasBeenMovedFrom(false)
{}
MoveTracker(MoveTracker const &)
: hasBeenMovedFrom(false)
{}
MoveTracker(MoveTracker && other)
: hasBeenMovedFrom(false)
{
if (other.hasBeenMovedFrom)
{
std::cout << "already moved!" << '\n';
}
else
{
other.hasBeenMovedFrom = true;
}
}
};
void foo(MoveTracker, MoveTracker) {}
int main()
{
using namespace std::placeholders;
std::function<void(MoveTracker)> func = std::bind(foo, _1, _1);
MoveTracker obj;
func(obj); // prints "already moved!"
}
这种行为是否为标准所允许?是否允许std::function
移动其参数?如果是这样的话,我们可以将bind
返回的包装转换为带有by-value参数的std::function
是否正常,即使这在处理多个占位符时触发意外行为?
指定std::function
将提供的参数传递给带有std::forward
的包装函数。例如,对于std::function
,函数调用运算符等效于
void operator(CopyableMovable a)
{
f(std::forward<CopyableMovable>(a));
}
由于std::forward
在t
不是引用类型时与std::move
等效,因此这是第一个示例中的移动之一。第二个可能来自于必须通过std::function
内部的间接层。
这也解释了您在使用std::bind
时遇到的问题,因为包装的函数:std::bind
也被指定为转发其参数,在这种情况下,它将被传递一个rvalue引用,该引用是由std::function
内部的std::forward
调用产生的。因此,绑定表达式的函数调用运算符将rvalue引用转发给每个参数。不幸的是,由于您重用了占位符,在这两种情况下,它都是对同一对象的rvalue引用,因此对于可移动类型,无论首先构造的哪个都将移动值,而第二个参数将得到一个空壳。
标准库函数bind()和function()定义于头文件<functional>中(该头文件还包括许多其他函数对象),用于处理函数及函数参数。bind()接受一个函数(或者函数对象,或者任何你可以通过”(…)”符号调用的事物),生成一个其有某一个或多个函数参数被“绑定”或重新组织的函数对象。(译注:顾名思义,bind()函数的意义就像它的函数名一样,是用来绑定函数调用的某些参数的。)例如: int
来自标书§4.2.7http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html#pathological-案例 它说: 这些更不可能是真正有用的代码。在此示例中,既不能转换为也不能转换为,因此这些函数甚至都不能使用普通成员语法调用。但是,您可以获取指向此类函数的指针并通过该指针调用它们。
在Java 8中,Stream有一个方法reduce: 累加器运算符是否允许修改其任一参数?我不这么认为,因为JavaDoc说累加器应该是非干涉的,尽管所有示例都谈到修改集合,而不是修改集合的元素。 举个具体的例子,如果我们有 假设整数是可变的,那么可以通过将第二个参数的值添加到第一个参数中(就地)来修改第一个参数吗? 我想不会,但我也想举一个例子,说明这种干扰在哪里会引起问题。
问题内容: 我拼凑了一个图片网站。基本模式是非常简单的MySQL,但是在尝试表示与图像相关联的可能的管理标志(“不合适”,“受版权保护”等)时遇到了一些麻烦。我目前的概念如下: (为了方便阅读而被截断;我发誓要搭配各种外键和索引) 在标志类型的查找表上是外键,并且您可以想象 应该 在上外键。现在的问题是,当第一次发出标志时,没有逻辑解析类型(我将其声明为的一种很好的用法)。但是,如果设置了值,则应
问题内容: URI(特别是HTTP URL)是否允许包含一个或多个空格字符?如果 必须 对URL 进行编码,这是通常遵循的约定还是合法的选择? 特别是,有人可以指向RFC指出 必须 对带有空格的URL 进行编码吗? 提出问题的动机: 在对网站进行Beta测试时,我注意到某些URL的构造带有空格。Firefox似乎做对了,这让我感到惊讶!但是我希望能够将开发人员指向RFC,以便他们觉得有必要修复这些
我试图检查在哪里失去了准确表示大整数的能力。所以我写了这个小片段: 这段代码似乎适用于所有编译器,除了clang。Clang生成一个简单的无限循环。戈德博尔特。 这是允许的吗?如果是,这是QoI问题吗?