16

我正在努力相处std::function。从这里的参考可以看出std::function's ctor 的参数应该是可调用的并且是可复制构造的。所以这里是一个小例子:

#include <iostream>
#include <type_traits>
#include <functional>

class A {
public:
    A(int a = 0): a_(a) {}
    A(const A& rhs): a_(rhs.a_) {}
    A(A&& rhs) = delete;
    void operator() ()
    {
        std::cout << a_ << std::endl;
    }

private:
    int a_;
};

typedef std::function<void()> Function;

int main(int argc, char *argv[])
{
    std::cout << std::boolalpha;
    std::cout << "Copy constructible: "
              << std::is_copy_constructible<A>::value << std::endl;
    std::cout << "Move constructible: "
              << std::is_move_constructible<A>::value << std::endl;
    //Function f = A();
    return 0;
}

我们有可调用、可复制构造但不可移动构造类。因为我相信这应该足以将它包装在Function. 但是,如果您取消注释注释行编译器会对删除的移动构造函数感到非常不安。这是ideone链接。GCC 4.8.0 也不编译这个。

那么,这是我误解了std::function还是 GCC 的错误行为?

4

2 回答 2

11

GCC 和 Clang 是正确的。

§17.6.3.1.1模板参数要求 [utility.arg.requirements]

表 20 - MoveConstructible 要求 [moveconstructible]。

  • T u = rv; u 相当于构造前的 rv 值。
  • T(RV);T(rv) 相当于构造前的 rv 值。

表 21 - CopyConstructible 要求(除了 MoveConstructible)[copyconstructible]。

  • Tu = v; v 的值不变,等价于 u。
  • 电视); v 的值不变,等价于 T(v)。

请注意:

CopyConstructible 要求(除了 MoveConstructible

即,如果某些东西是CopyConstructible它也必须是MoveConstructible。尽管可以将移动作为副本实施。

更新:

虽然我觉得有趣的是,C++11 标准似乎没有is_copy_constructible根据CopyConstructible进行定义,即它们并不完全相同,is_copy_constructible但更宽松,因为它只需要:

§20.9.4.3类型属性 [meta.unary.prop]

表 49 - 类型属性谓词

  • is_copy_constructible<T>; is_constructible<T,const T&>::value 为真。
于 2013-07-25T07:51:49.450 回答
4

您误解了删除规范的目的。移动构造函数不是默认实现的。如果您尝试在没有 move-ctor 的情况下移动对象,它将被复制。如果您将移动构造函数指定为已删除,它将尝试调用它,然后看到它已被删除。这意味着:您不能复制临时对象。删除 move-constructor 语句,它将起作用。

编辑 - 澄清:

如果未声明移动构造函数(其中 =delete 是声明),则来自临时对象的构造将调用复制构造函数(来自 const 引用)。如果你声明一个移动构造函数,一个临时对象的构造将尝试调用它。所以如果你声明一个move-ctor被删除,它会尝试调用一个delete函数,这会导致错误。如果您不声明它,它将导致调用复制 ctor。

这就是为什么您的示例不起作用的原因,如果您没有声明它,std::function 只会使用 copy-ctor。

默认情况下,我的意思是:如果没有声明就实现,因为它发生在 copy- 或 default-ctor 中。

于 2013-07-25T07:52:51.683 回答