Pregunta

I'm trying to write a function that will work on a std::array of variable size, eg:

std::array a<int,5>={1,2,3,4,5};
std::array b<int,3>={6,7,8};

myFunc(a);
myFunc(b);

void myFunc(std::array &p)
{
cout << "array contains " << p.size() << "elements"; 
}

However, it doesn't work unless I specify the size, but I want the function to get the size from the array. I really didn't want the copying and dynamic allocation that vector uses, I want to use the space allocated by std::array() and don't want the compiler creating a copy of the function for every possible size of array.

I thought about creating a template that works like array but will take a pointer to existing data rather than allocating it itself, but don't want to reinvent the wheel.

Is this possible somehow?

¿Fue útil?

Solución

template<typename T, size_t N>
void myFunc(std::array<T, N> const &p) {
    cout << "array contains " << p.size() << "elements"; 
}

std::array is not a class and cannot be used like a class. It's a template, and you must instantiate the template in order to get a class that can be used like a class.

Also, the size is part of the type of an array. If you want a container where the size isn't part of the type then you can use something like std::vector. Alternatively you can write a template that works for any object that has the functionality you need:

template<typename Container>
void myFunc(Container const &p) {
    cout << "Container contains " << p.size() << "elements"; 
}

Otros consejos

Prefer the STL way : pass iterators (by value) instead of containers to your functions. And templatize your functions.

Your code will integrate much better with the standard algorithms, and will work equally will with std::array or other standard containers.

e.g. :

template<class InputIterator>
void myFunc (InputIterator first, InputIterator last);

What you really want is something like the proposed std::array_ref (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3334.html) which accepts any size and just contains a pointer range (or a pointer and count depending on how it's implemented), not template bloat for each possible container type, heap allocated containers, or pairs of iterators at every call point.

Another option people forget about though is std::initializer_list which is effectively array_ref, a lightweight contiguous homogeneous view of items. Although intended for constructors (where the name 'initializer' makes the most sense), they can be consumed by generic functions too. Note the contents are not copied when passed, just a pointer range, meaning you don't need to (and shouldn't) pass initializer_list by reference.

It lets you pass the series of numbers directly in the function call:

void myFunc(std::initializer_list<int> p)
{
    cout << "array contains " << p.size() << "elements"; 
}

myFunc({1, 2, 3, 4, 5});
myFunc({6, 7, 8});

Or via an intermediate variable:

std::initializer_list<int> a = {1, 2, 3, 4, 5};
std::initializer_list<int> b = {6, 7, 8};
auto c = {1, 2, 3, 4, 5};
auto d = {6, 7, 8};
myFunc(a);
myFunc(b);
myFunc(c);
myFunc(d);

Or even, it appears, adapted from the fixed-size std::array using a constructor overload which takes a begin/end pair.

std::array<int, 5> e = {1, 2, 3, 4, 5};
std::array<int, 3> f = {6, 7, 8};
myFunc(std::initializer_list<int>(e.data(), e.data() + e.size()));
myFunc(std::initializer_list<int>(f.data(), f.data() + f.size()));

Though, I don't see this constructor overload listed on cppreference.com, nor in N4166. So this overload may be not standard and only found in Dinkumware's STL (used by Visual Studio 2015). Also, there are no implicit conversions from array/vector leaving you to ultimately write an intermediate helper template function anyway (or write more code than simply passing two ranges would be), which is too bad. Ideally std::array would support an operator method that promoted to initializer_list or array_ref would be adopted in the standard.

This is because the size is part of type std::array.

template< 
    class T, 
    std::size_t N 
> struct array;

Array with different size is different type. You should use a template function and write:

template< typename T, size_t N>
void myFunc( std::array<T, N> const &p) {
    std::cout << "array contains " << p.size() << "elements"; 
}

http://en.cppreference.com/w/cpp/container/array

I want to throw my suggestion in addition to the ones that already have been suggested.

template<size_t N>
void myFunc(std::array<int, N> const &p) {
    cout << "array contains " << N << "elements"; 
}

By the way, your variable declarations need to be:

std::array<int,5> a={1,2,3,4,5};  // <int, 5> needs to move to right after array.
std::array<int,3> b={6,7,8};
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top