Должна ли черта типа справиться с такими случаями, как std::vector < std::unique_ptr <int> >
и обнаружить, что это не копируемый конструкт?
Вот пример на https://ideone.com/gbcRUa (работает g ++ 4.8.1)
#include <type_traits>
#include <vector>
#include <iostream>
#include <memory>
int main()
{
// This prints 1, implying that it's copy constructible, when it's clearly not
std::cout << std::is_copy_constructible< std::vector<std::unique_ptr<int> > >::value << std::endl;
return 0;
}
Если это правильное поведение для is_copy_constructible
Есть ли способ обнаружить, что конструкция копии плохо сформирована? Ну, кроме того, что он не компилируется.
Это из-за недостатка в дизайне std::vector
, std::vector
определяет конструкцию копии, даже если она не скомпилируется, и полагается на пользователей std::vector
не вызывать метод, если он не скомпилируется.
Альтернативный дизайн — SFINAE блокирует вызов метода, если тип, содержащийся в vector
не имеет конструктора копирования. Тем не мение, std::vector
был разработан до разработки современной техники SFINAE.
Возможно, он будет встроен в новую итерацию C ++, так как будет очень мало кода, который может сломаться. Нельзя сказать, что ни один код не сломается, потому что у вас может быть код, основанный на том факте, что std::is_copy_constructible< std::vector< no_copy_type > >
является std::true_type
или эквивалентные выражения, но это довольно странная зависимость.
Помимо того, что std::vector
он старше техник SFINAE, которые могли бы решить эту проблему, поэтому делать это с SFINAE довольно грязно (так как SFINAE — грязная техника). Новый концепт-лайт, предложенный для C ++ 1y, может сделать его чище и более заманчивым для включения в новую итерацию языка.
Моя работа, когда у меня есть контейнер, который должен знать, можно ли безопасно скопировать, сравнить и упорядочить содержащийся объект, состоит в том, чтобы специализироваться на std::vector
в классе настраиваемых признаков и использовать значение класса настраиваемых признаков для содержащегося типа. Это лоскутное решение, и довольно навязчивое.
template<template<typename>class test, typename T>
struct smart_test : test<T> {};
template<template<typename>class test, typename T, typename A>
struct smart_test<test, std::vector<T,A>> : test<T> {}
что дает нам:
template<typename T>
using smart_is_copy_constructible = smart_test< std::is_copy_constructible, T >;
и подобное для <
а также ==
, Я могу добавить больше специализаций, когда столкнусь с большим количеством типов контейнеров, которые действительно должны перенаправить свои свойства в свои данные, или я мог бы написать более интересный контейнер-тест SFINAE и выполнить traits, извлечь базовый тип-значение и отправить вопрос в тест. на типе значения.
Но по моему опыту, я в основном в конечном итоге делать эти тесты на std::vector
,
В таблице 49 стандарта C ++ 11 перечислены условия, которым должен соответствовать класс is_copy_constructable<T>::value
чтобы быть правдой, и это, к сожалению, не так много
is_constructable<T, const T&>::value
являетсяtrue
Так что если std::vector<T>
имеет конструктор копирования, он проходит тест.