Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::vector as a template function argument

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!

like image 340
Prettygeek Avatar asked Sep 30 '13 12:09

Prettygeek


People also ask

Is STD A vector template?

Vectors, or std::vector , are a template class in the STL (Standard Template Library). But what does that mean? They are a more flexible, refined, and efficient replacement for arrays, which are used in the C programming language (and on which the C++ language is based).

Is Vector a template in C++?

vector is a template class, which can be instantiated with a type, in the format: vector<int> , vector<double> , vector<string> . The same template class can be used to handle many types, instead of repeatably writing codes for each of the type.

How do you declare a template function?

To instantiate a template function explicitly, follow the template keyword by a declaration (not definition) for the function, with the function identifier followed by the template arguments. template float twice<float>( float original ); Template arguments may be omitted when the compiler can infer them.


1 Answers

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.

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

like image 61
Yakk - Adam Nevraumont Avatar answered Sep 18 '22 13:09

Yakk - Adam Nevraumont