【问题标题】:std::function for not MoveConstructible function object in gcc用于 gcc 中非 MoveConstructible 函数对象的 std::function
【发布时间】:2013-07-25 07:33:22
【问题描述】:

我正在努力与std::function 相处。从参考here 可以看出std::function 的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 的错误行为?

【问题讨论】:

  • 刚用clang++试过,同样的问题。
  • 认为在重载决策期间仍会考虑deleted 函数,在这种情况下,它会在复制构造函数之前被选中并导致错误。为了更正,删除移动构造函数的声明,因为用户声明的构造函数的存在不会隐式生成。此外,请参阅 this question 了解 is_move_constructible 信息。

标签: c++ gcc c++11


【解决方案1】:

GCC 和 Clang 是正确的。

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

表 20MoveConstructible 要求 [moveconstructible]。

  • T u = RV; u 等价于 rv 的值 施工前。
  • T(RV); T(rv) 等价于 rv 的值 施工前。

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

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

注意:

CopyConstructible 要求(除了 MoveConstructible

即如果某物是CopyConstructible,它也必须是MoveConstructible。虽然可以将移动作为副本实施。

更新:

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

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

表 49 - 类型属性谓词

  • is_copy_constructible; is_constructible::value 为真。

【讨论】:

    【解决方案2】:

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

    编辑 - 澄清:

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

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

    默认情况下,我的意思是:如果没有声明就实现,就像复制或默认ctor一样。

    【讨论】:

      猜你喜欢
      • 2015-09-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-09
      • 1970-01-01
      • 2021-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多