1

Say that I have 3 variables:

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

I can initialize any of these if I know the size is 3:

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

Where X is either, vec, stat, or dyn. But I'd like to be able to do this in a template just by passing in X again. What I'd need in order to do this is:

  1. The contained type
  2. The container size

Can I get that in a function like:

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

Or am I unable to extract size information from the unique_ptr? Or type in a universal fashion? (I've marked this question C++17 in the hopes that size can be used.)

Community
  • 1
  • 1
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • 1
    Are you looking for [`std::iota`](http://en.cppreference.com/w/cpp/algorithm/iota)? – ildjarn Feb 25 '16 at 23:07
  • @ildjarn `iota` is great if you can use it. In my example here: http://stackoverflow.com/a/35630222/2642059 you'll see I do use `iota`. But how would I get iterators in the same way for all of these? I can't use `begin` or `end` on `dyn`. – Jonathan Mee Feb 26 '16 at 02:05

3 Answers3

2

You are not going to be able to get the size from the unique pointer. When you use auto dyn = make_unique<int[]>(3); it gets translated to

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

Which is a pointer and we lose the size information. All the array overload does for unique pointer is change the delete call in the destruction to delete[]. If you want to use an unique_ptr "array" then you wil need to pass the size.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
2

You can't do this for unique_ptr<T[]> - that's still just a raw pointer that doesn't have any idea what its size is.

But any other container, you don't even need size(). Just C++11 suffices:

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

You can add SFINAE or a static_assert on top of that to ensure that the elements of T are actually assignable to 3, but otherwise that suffices.

Barry
  • 286,269
  • 29
  • 621
  • 977
1

If you’re using a loop over the respective contents, then you actually don’t care for the actual containers or holders. This is a good time to be using a pair of iterators, an array view, or a range. E.g.:

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);

Note that you either have to hardcode the size 3 in the std::unique_ptr<int[]> case, or keep track of it yourself somewhere in a variable. The size information is not available otherwise.

Luc Danton
  • 34,649
  • 6
  • 70
  • 114