Работа с unique_ptr‹int[]›, vector‹int› и int[] в шаблонной функции

Скажем, у меня есть 3 переменные:

vector<int> vec(3);
int stat[3];
auto dyn = make_unique<int[]>(3);

Я могу инициализировать любой из них, если я знаю, что размер равен 3:

for(auto i = 0; i < 3; ++i) X[3] = i;

Где X это vec, stat или dyn. Но я хотел бы иметь возможность сделать это в шаблоне, просто снова передав X. Что мне нужно, чтобы сделать это:

  1. Содержащийся тип
  2. Размер контейнера

Могу ли я получить это в такой функции, как:

template <typename T>
void init(T& X);

Или я не могу извлечь информацию о размере из unique_ptr? Или набрать универсальный мод? (Я отметил этот вопрос С++ 17 в надежде, что можно будет использовать size.)


person Jonathan Mee    schedule 25.02.2016    source источник
comment
Вы ищете std::iota?   -  person ildjarn    schedule 26.02.2016
comment
@ildjarn iota великолепен, если вы можете его использовать. В моем примере здесь: stackoverflow.com/a/35630222/2642059 вы увидите, что я использую iota. Но как мне получить одинаковые итераторы для всех них? Я не могу использовать begin или end на dyn.   -  person Jonathan Mee    schedule 26.02.2016


Ответы (3)


Вы не сможете получить размер по уникальному указателю. Когда вы используете auto dyn = make_unique<int[]>(3);, он переводится на

make_unique<int[]>(new int[3]())

Это указатель, и мы теряем информацию о размере. Все, что перегрузка массива делает для уникального указателя, — это изменение вызова delete в уничтожении на delete[]. Если вы хотите использовать «массив» unique_ptr, вам нужно будет передать размер.

person NathanOliver    schedule 25.02.2016

Вы не можете сделать это для unique_ptr<T[]> - это всего лишь необработанный указатель, который не знает, каков его размер.

Но любой другой контейнер вам даже не нужен size(). Достаточно С++ 11:

 template <class T>
 void init(T& container) {
     for (auto& elem : container) {
         elem = 3;
     }
 }

Вы можете добавить SFINAE или static_assert поверх этого, чтобы гарантировать, что элементы T действительно могут быть назначены 3, но в остальном этого достаточно.

person Barry    schedule 25.02.2016

Если вы используете петлю для соответствующего содержимого, то вам на самом деле не нужны контейнеры или держатели. Сейчас самое время использовать пару итераторов, представление массива или диапазон. Например.:

template<typename It>
void init(It first, It last)
{
    // or use an algorithm, e.g. std::iota(first, last, 0)
    int i = 0;
    for(; first != last; ++last, ++i) *first = i;
}

// use as:
using std::begin;
using std::end;
init(begin(vec), end(vec));
init(begin(stat), end(stat));
init(dyn.get(), dyn.get() + 3);

Обратите внимание, что вам нужно либо жестко закодировать размер 3 в случае std::unique_ptr<int[]>, либо отслеживать его самостоятельно где-то в переменной. В противном случае информация о размере недоступна.

person Luc Danton    schedule 26.02.2016