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!
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::vector
s 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 T
s 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.