2013-07-25 4 views
16

Я стараюсь ладить с std::function. Из ссылки here видно, что аргумент std::function ctor должен быть доступен для копирования и копирования. Итак, вот небольшой пример:std :: function for not MoveConstructible function object in gcc

#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?

+0

Просто попробовал с clang ++, там же проблема. –

+3

I _think_ функция 'delete'd по-прежнему рассматривается во время разрешения перегрузки и в этом случае выбирается перед конструктором копирования и вызывает ошибку. Чтобы исправить, удалите объявление конструктора перемещения, поскольку он не будет неявно сгенерирован из-за существования объявленного пользователем конструктора. Кроме того, см. [Этот вопрос] (http://stackoverflow.com/questions/16897845/move-member-function-generation) для информации 'is_move_constructible'. – hmjd

+1

@hmjd Yup. http://stackoverflow.com/q/14085620/1171191 – BoBTFish

ответ

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].

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

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

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

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

Update:

Хотя я нахожу интересным, что стандарт 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 & > :: значение истинно.
4

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

Edit - Разъяснение:

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

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

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