C++ 是否允许'std::function'移动其参数?

C++ 是否允许'std::function'移动其参数?,c++,function,c++11,bind,C++,Function,C++11,Bind,在处理时,我注意到GCC(v4.7)对std::function的实现在参数按值取值时会移动参数。以下代码显示了此行为: #include <functional> #include <iostream> struct CopyableMovable { CopyableMovable() { std::cout << "default" << '\n'; } CopyableMova

在处理时,我注意到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

标准允许这种行为吗?
std::function
是否允许移动其参数?如果是这样,我们可以将
bind
返回的包装器转换为带有by-value参数的
std::function
是否正常,即使在处理多次出现的占位符时,这会触发意外行为?

std::function
被指定为使用
std::forward
将提供的参数传递给包装函数。e、 g.对于
std::function
,函数调用运算符等效于

void operator(CopyableMovable a)
{
    f(std::forward<CopyableMovable>(a));
}
void运算符(可复制可移动a)
{
f(标准:远期(a));;
}
由于当
T
不是引用类型时,
std::forward
相当于
std::move
,因此这是第一个示例中移动的原因之一。第二种可能来自于必须通过
std::function
中的间接层


这也解释了使用
std::bind
作为包装函数时遇到的问题:
std::bind
也被指定转发其参数,在这种情况下,它被传递一个由
std::forward
内部调用
std::function
产生的右值引用。因此,绑定表达式的函数调用运算符将向每个参数转发一个右值引用。不幸的是,由于您重用了占位符,因此在这两种情况下它都是对同一对象的右值引用,因此对于可移动类型,无论先构造哪个类型,都会移动该值,第二个参数将得到一个空壳。

在我看来,占位符的问题比
std::function
更大。也就是说,当创建<代码> TIA<代码>时,移动从原来的参数使用到两个预期的输出。有趣的是,Visual C++ 11编译器在第一个示例中打印“默认复制移动”,并且在第二个示例中不打印“已经移动”。我想知道这个额外的动作是否来自std::function和/或perfect forwarding的内部工作。@MatthieuM。你能详细说明一下吗?我不太熟悉占位符的实现。如果问题来自占位符,那么在使用
auto
推断“绑定包装器”类型时,而不是使用
std::function
?@LucDanton(在后一种情况下)函数对象(包装器)的参数时,为什么不出现问题将是类型为
MoveTracker&
的左值引用,并将作为左值引用转发到
foo
,两次,导致这些左值引用的两个副本构造。哦,我从未意识到
std::forward
等同于
std::move
!这解释了很多事情。
void operator(CopyableMovable a)
{
    f(std::forward<CopyableMovable>(a));
}