简体   繁体   中英

function template with stl container as an input

I am getting compilation error is following code. I thought this should have worked in c++ Can anybody help me to understand what is wrong here.

template < typename elem_type>
elem_type *find2( std::vector<elem_type>& vec, elem_type value) {
    for ( int i = 0; i < vec.size(); ++i) {
        if ( vec[i] == value ) {
            return &vec[i];
        }
    }
    return 0;
}
int main( int argc, char **argv) {
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    std::vector<int> vec( arr, arr+10);     
    int value = 9;
    int *ptr1 = find2(vec,value);
}

following is the compilation error

1>          d:\personal\work\find\find\find.cpp(25) : see reference to function template instantiation 'elem_type *find2<int>(std::vector<_Ty> &,elem_type &)' being compiled
1>          with
1>          [
1>              elem_type=int,
1>              _Ty=int
1>          ]

compiler is Visual Studio 11

It is best to use a variable of the same type as the index used in the container. In this case, you want a size_t or a size_type . They correspond with the types used in the vector's size and operator[] functions.

for (size_t i = 0; i < myVector.size(); ++i)
{
    myVector[i]++;
}

If you need to iterate in reverse, simply maintain an internal index.

for (size_t i = 0; i < myVector.size(); ++i)
{
    size_t j = myVector.size() - i - 1;
    myVector[j]++;
}

If you need to perform signed math, again, maintain an internal casting.

for (size_t i = 0; i < myVector.size(); ++i)
{
    int j = (int)i;
    myVector[i] += j;
}

The fundamental problem you have is that you are mixing signed and unsigned integers. Your index variable is a signed type, but the vector's size() member function returns an unsigned type. Mixing types like this can cause errors. If a signed value like -1 gets assigned to an unsigned variable, a very large value is usually the result.

The idiomatic way to iterate over a standard library container is to use standard library iterators.

for (std::vector<elem_type>::iterator it=vec.begin(); it<vec.end(); ++it)
{
    if ( *it == value ) {
        return &(*it);
    }
}

In this line,

    for ( int i = 0; i < vec.size(); ++i ) {

you are comparing the signed int variable i to the unsigned size_t result of vec.size() .

The compiler warns because such a comparision is unsafe in the face of implicit promotions in C++. i is promoted to size_t . If i were (hypothetically) negative, that would produce a really huge value, and would thus produce an unexpected comparision result.

A simple cure is to

    #include <stddef.h>
    typedef ptrdiff_t Size;
    typedef Size Index;

and then do eg

    for ( int i = 0; i < Size( vec.size() ); ++i ) {

You will probably get at least one answer recommending the apparently simpler

    for ( size_t i = 0; i < vec.size(); ++i ) {

but this is problematic for the same reason that the compiler warned: using unsigned integers as numbers risks getting very weird and unexpected results, buggy results, due to implicit promotions and in general conversion from negative number to unsigned, or vice versa.

Even better than the casting above, define a countOf function like

    template< class Container >
    Size countOf( Container const& c ) { return v.size(); }

    template< class Elem, Size n >
    Size countOf( Elem (&)[n] ) { return n; }

and then write just

    for ( int i = 0; i < countOf( vec ); ++i ) {

And best, forget about that indexing and use iterators:

    for ( auto it = vec.begin(); it != vec.end(); ++it ) {

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM