31

I want to make a class method that takes a std::vector reference as an argument and I want to use it with different types of data.

The function should look like:

void some_function(const std::vector & vect){ //do something with vector }

and I want use it with for example:

std::vector<int> v1;
some_function(v1);
std::vector<string> v2;
some_function(v2);

I hope that I made my point clear. Do I have to make a template method like that:

template<class T>
void some_function(std::vector<T> & vect){}

or can I do it in another way? If I have to, please tell me how I can write that method in a class.

Thanks for help!

Andreas
  • 5,393
  • 9
  • 44
  • 53
Prettygeek
  • 2,461
  • 3
  • 22
  • 44
  • 1
    Yes, that's the way to do it. Or are you asking something else? – jrok Sep 30 '13 at 12:31
  • 2
    What's wrong with you suggested? – Asaf Sep 30 '13 at 12:32
  • 2
    The answer to this question is self sufficient. Just to add that if anyone want to iterate such vectors then use : `for(typename vector::const_iterator it = vect.begin(); it != vect.end(); ++it)` – rakesh sinha Feb 23 '17 at 06:12

1 Answers1

47

The right way for a template function to accept any std::vector by const& is:

template<typename T, typename A>
void some_func( std::vector<T,A> const& vec ) {
}

the second argument is the "allocator", and in some advanced usage of std::vector it will not be the default one. If you just accept std::vector<T>, your some_func will reject std::vectors with alternative allocators.

Now, there are other ways to approach this that I will list quickly. I will list them in decreasing cost:benefit ratio -- the one above is probably what you want, and the next one is sometimes useful, and after that I will branch off into over engineered cases that are rarely worth considering (but might be useful in some corner cases).

You could accept an arbitrary type T by T&& then test to determine if typename std::remove_reference<T>::type is a kind of std::vector. This would allow you to do "perfect forwarding" of the incoming std::vector. It would also let you change the predicate you use to test to accept more than just a std::vector: for the most part, const& to std::vector probably just needs some arbitrary random-access container.

A ridiculously fancy way would be to do a two-step function. The second step takes a type-erased random-access range view (or just a range-view if you don't need random access) for a fixed type T with SFINAE to ensure that the incoming object is compatible, the first step deduces the container type of the passed in type and calls the second step in a SFINAE context (auto some_func(...)->decltype(...)).

As type erasure of std::vector<T> const& to a random-access range view of contiguous Ts doesn't lose much functionality, an advantage would be that you could guarantee that the body of your function is exactly the same for std::vector<T> const& and for T[n] and for std::array<T,n>.

It isn't a big advantage, especially for the boilerplate required.

may make this much easier, because the multi-step SFINAE above will collapse into a few requires clauses.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • Hey, I think that if I write like **template void some_func( T container ) {}** This code is also valid, right? – codosopher May 18 '23 at 14:39
  • @codosopher `some_func( T const& container )` if you don't want to copy it yes. But this won't constrain the argument to be a `std::vector`. – Yakk - Adam Nevraumont May 18 '23 at 15:02
  • Well, I think that the only difference between `some_func( T& container )` and `some_func( std::vector& container )` will be that it limits performing operations specific to std::vector. – codosopher May 18 '23 at 20:48
  • *But this won't constrain the argument to be a std::vector.* what do you mean by that. If you mean that it won't accept vector as a parameter, I applied it and it runs. – codosopher May 18 '23 at 20:59
  • 1
    @codosopher A parameter is *constrained* to a category *X* if things outside of the category *X* are not accepted as arguments. To constrain is to restrict. `T& container` will take things that are not container or vectors and attempt to compile the body of the template; if that succeeds (by happenstance or design) it will go forward. The ones that constrain the argument will only accept vectors (or, in other cases, container) that pass whatever the constraint requirement is. – Yakk - Adam Nevraumont May 19 '23 at 14:07