Предположим, пространство имен std
на протяжении.
Проект комитета C ++ 14 N3690 определяет std::make_unique
таким образом:
[n3690: 20.9.1.4]:
unique_ptr
создание [Unique.ptr.create]
template <class T, class... Args> unique_ptr<T> make_unique(Args&&... args);
1 Примечания: эта функция не должна участвовать в разрешении перегрузки, если только
T
это не массив.
2 Возвращает:unique_ptr<T>(new T(std::forward<Args>(args)...)).
template <class T> unique_ptr<T> make_unique(size_t n);
3 Примечания: эта функция не должна участвовать в разрешении перегрузки, если только
T
массив неизвестных границ
4 Возвращает:unique_ptr<T>(new typename remove_extent<T>::type[n]()).
template <class T, class... Args> unspecified make_unique(Args&&...) = delete;
5 Примечания: эта функция не должна участвовать в разрешении перегрузки, если только
T
массив известных границ
Теперь мне кажется, что это почти так же ясно, как грязь, и я думаю, что это требует большей экспозиции. Но, если оставить в стороне этот редакционный комментарий, я думаю, что я расшифровал значения каждого варианта:
template <class T, class... Args> unique_ptr<T> make_unique(Args&&... args);
Ваш болотный стандарт make_unique
для не-массив типов. Предположительно, «замечание» указывает на то, что некоторая форма статического утверждения или трюка SFINAE состоит в том, чтобы предотвратить успешное создание шаблона, когда T
тип массива
На высоком уровне рассматривайте его как смарт-указатель, эквивалентный T* ptr = new T(args);
,
template <class T> unique_ptr<T> make_unique(size_t n);
Вариант для типов массивов. Создает динамически распределенный массив n
× Ts
и возвращает его, завернутый в unique_ptr<T[]>
,
На высоком уровне рассматривайте его как смарт-указатель, эквивалентный T* ptr = new T[n];
,
template <class T, class... Args> unspecified make_unique(Args&&...)
Недопустимое. «неопределенные«вероятно будет unique_ptr<T[N]>
,
В противном случае смарт-указатель будет эквивалентен чему-то недопустимому T[N]* ptr = new (keep_the_dimension_please) (the_dimension_is_constexpr) T[N];
,
Прежде всего, я прав? И если так, что происходит с третьей функцией?
Если он запрещает программистам пытаться динамически размещать массив, предоставляя аргументы конструктора для каждого элемента (так же, как new int[5](args)
невозможно), тогда это уже покрыто тем фактом, что первая функция не может быть реализована для типов массивов, не так ли?
Если это там, чтобы предотвратить добавление к языку конструкции, как T[N]* ptr = new T[N]
(где N
это какой-то constexpr
) ну и зачем? Разве это не было бы полностью возможно для unique_ptr<T[N]>
существовать, которое оборачивает динамически распределенный блок N
× T
s? Будет ли это настолько плохой вещью, что комитет изо всех сил пытается запретить его создание, используя make_unique
?
Почему make_unique<T[N]>
запрещено?
Цитировать из оригинальное предложение:
T[N]
По состоянию на N3485,
unique_ptr
не обеспечивает частичную специализацию дляT[N]
,
Тем не менее, пользователи будут сильно склонны писатьmake_unique<T[N]>()
, это
это беспроигрышный сценарий. возвратеunique_ptr<T[N]>
выбрал бы основной
шаблон для отдельных объектов, что странно. возвратеunique_ptr<T[]>
будет исключением из ироничного правила, что
make_unique<something>()
возвращаетсяunique_ptr<something>
, Следовательно, это
предложение делаетT[N]
плохо сформированный здесь, позволяющий реализации излучать
полезныйstatic_assert
Сообщения.
Автор предложения, Стефан Т. Лававей, иллюстрирует эту ситуацию в это видео на Core C ++ (любезно предоставлено Крис), начиная с минуты 1:01:10 (более или менее).
Для меня третья перегрузка выглядит излишней, так как не меняет того факта, что другие перегрузки не будут совпадать T[N]
и это делает не кажется, помогают генерировать лучшие сообщения об ошибках. Рассмотрим следующую реализацию:
template< typename T, typename... Args >
typename enable_if< !is_array< T >::value, unique_ptr< T > >::type
make_unique( Args&&... args )
{
return unique_ptr< T >( new T( forward< Args >( args )... ) );
}
template< typename T >
typename enable_if< is_array< T >::value && extent< T >::value == 0, unique_ptr< T > >::type
make_unique( const size_t n )
{
using U = typename remove_extent< T >::type;
return unique_ptr< T >( new U[ n ]() );
}
Когда вы пытаетесь позвонить std::make_unique<int[1]>(1)
сообщение об ошибке перечисляет обоих кандидатов как отключенных enable_if
, Если вы добавите третью удаленную перегрузку, в сообщении об ошибке будут перечислены три кандидата. Кроме того, так как он указан как =delete;
вы не можете предоставить более значимое сообщение об ошибке в теле третьей перегрузки, например, static_assert(sizeof(T)==0,"array of known bound not allowed for std::make_shared");
,
Вот живой пример в случае, если вы хотите поиграть с ним.
Тот факт, что третья перегрузка закончилась в N3656 и N3797, возможно, связана с историей того, как make_unique
был разработан со временем, но я думаю, что только STL может ответить на это 🙂