2016-11-10 6 views
3

Я играю с этой небольшой фрагмент кода:C++ идеальный вперед от копирования только типы в make_tuple

#include <tuple> 

struct copy_only 
{ 
    copy_only() = default; 
    copy_only(copy_only&&) = delete; 
    copy_only(const copy_only&) = default; 
}; 

template <typename ...Ts> 
void foo(Ts&& ...xs) 
{ 
    auto t = std::make_tuple(std::forward<Ts>(xs)...); 
    (void) t; 
} 

int main() 
{ 
    foo(copy_only{}); 
} 

Он компилирует штрафа с gcc7 и clang3.6, clang3.7, clang3.8 (Wandbox), и clang8.0 (macOS Sierra). Он не компилируется с clang3.9, g ++ 6.2 (macOS Sierra), а также с clang4.0 (Wandbox). Все они жалуются на конструктор удаленных перемещений.

Он отлично работает с типами перемещения. По крайней мере, на вышеупомянутых компиляторах доступно Wandbox.

Является ли этот код примером правильного пути общей совершенной пересылки в кортеж в C++ 14?

+0

Если вы удалите 'copy_only (copy_only &&) = delete;', этот конструктор не будет сгенерирован, и можно будет выбрать перегрузку копии. В настоящее время конструктор перемещения лучше подходит. – Jarod42

+0

@ Jarod42 это правильно, но зачем он компилируется с gcc и старше clang? – krzaq

+0

@kraz: в C++ 1z 'auto t = ..' выполнит копирование, не требуя копии« существование ». – Jarod42

ответ

1
auto t = std::make_tuple(std::forward<Ts>(xs)...); 

Это действительно правильный способ пересылки аргументов в кортеж.

Ошибки компиляции, вызванные явным объявлением конструктора перемещения , удаляются. Обычно, если вы объявили конструктор копирования, он будет опущен, а в контекстах перемещения будет выбран конструктор копирования - как это было с C++ 98. Но поскольку вы явно заявили об этом, он участвует в разрешении перегрузки и вызывает неправильное формирование кода, если он выбран.

Вот полезный график любезно Говард Hinannt: chart

Это может быть решена путем удаления обижая строки из определения класса:

struct copy_only 
{ 
    copy_only() = default; 
    //copy_only(copy_only&&) = delete; 
    copy_only(const copy_only&) = default; 
}; 

Теперь, что ли код должен компилироваться или нет: насколько я могу судить, он должен. шаг конструктора tuple «s определяется как:

tuple(tuple&& u) = default;

Требуется: is_move_constructible<Ti>::value верно для всех я.

С copy_only не может быть конструктивным, его нельзя объявлять и не должны участвовать в разрешении перегрузки.

+0

Существует также реализация 'tuple', которая играет определенную роль. – Jarod42

+0

@ Jarod42 Я только что видел ваш комментарий. Я не уверен, что конструктор удаленных перемещений будет означать, что тип не работает конструктивно или нет. – krzaq

+1

Это грязно. 'is_move_constructible ' в основном 'is_constructible ' для ссылочных типов, что является ложным для 'copy_only', потому что разрешение перегрузки выбирает удаленный ctor. OTOH, '= default;' усложняет вещи, потому что дефолтное перемещение ctor определяется как удаленное, если, помимо прочего, разрешение перегрузки для перемещения подобъекта выбирает удаленный ctor, но такое перемещение по умолчанию с по умолчанию игнорируется разрешением перегрузки, и если это произойдет, то 'is_move_constructible >' истинно, потому что он использует копию ctor. –