Std:: function for not Объект функции MoveConstructible в gcc

Я пытаюсь ладить с std::function. Из справки здесь можно увидеть, что аргумент 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?

Ответы

Ответ 1

GCC и Clang верны.

§17.6.3.1.1 Требования к аргументам шаблона [utility.arg.requirements]

Таблица 20 - Требования MoveConstructible [moveconstructible].

  • T u = rv; u эквивалентно значению rv перед строительством.
  • Т (с.в.); T (rv) эквивалентно значению rv перед строительством.

Таблица 21 - Требования к CopyConstructible (в дополнение к MoveConstructible) [copyconstructible].

  • T u = v; значение v не изменяется и эквивалентно u.
  • Т (V); Значение v не меняется и эквивалентен T (v).

Обратите внимание:

CopyConstructible требования (в дополнение к MoveConstructible)

т.е. если что-то является CopyConstructible, оно также должно быть MoveConstructible. Хотя это прекрасно, чтобы реализовать перемещение как копию.

Update:

Хотя мне кажется интересным, что стандарт С++ 11, по-видимому, не определяет is_copy_constructible в терминах CopyConstructible, то есть они не совсем одинаковы, is_copy_constructible более расслаблен, поскольку он требует только:

§20.9.4.3 Свойства типа [meta.unary.prop]

Таблица 49 - Предикаты свойств типа

  • is_copy_constructible < Т > ; is_constructible < T, const T & > :: значение истинно.

Ответ 2

Вы неправильно поняли цель спецификации удаления. Конструктор move не используется по умолчанию. Если вы попытаетесь переместить объект без move-ctor, он просто будет скопирован. Если вы укажете конструктор move как удаленный, он попытается вызвать его, а затем увидеть, как он удален. Это означает: вы не можете скопировать временный объект. Удалите инструкцию move-constructor и она будет работать.

Изменить - Уточнение:

Если конструктор-конструктор не объявлен (где = delete - объявление), тогда конструкция из временного объекта вызовет конструктор-копию (из ссылки const). Если вы объявите конструктор перемещения, конструкция из временного объекта попытается вызвать это. Поэтому, если вы объявляете удаление move-ctor, оно попытается вызвать функцию удаления, что приведет к ошибке. Если вы не объявите его, это приведет к вызову копии ctor.

Вот почему ваш пример не работает, если бы вы не объявили, что std:: function просто использует copy-ctor.

По умолчанию я имел в виду: реализован, если не объявлен, как это происходит с копией или по умолчанию-ctor.