简体   繁体   中英

wrapping template function and <unresolved overloaded function type

I have problem with my wrapping function.

template <typename Iter, typename SomeFunction>                         
void wrap(Iter first, Iter last, SomeFunction someFunction)
{
  someFunction(first, last);
}

I would like to use it like this:

template <typename Iter>
void fill5(Iter first, Iter last)
{
    fill(first, last, 5); 
}
int main()
{
    vector<int> v(100, -1);
    wrap(v.begin(), v.end(), fill5);

}

But I get

test.cpp: In function ‘int main()’:
test.cpp:16:40: error: no matching function for call to ‘wrap(std::vector<int>::iterator, std::vector<int>::iterator, <unresolved overloaded function type>)’
test.cpp:16:40: note: candidate is:
wrap.h:6:6: note: template<class Iter, class SomeFunction> void wrap(Iter, Iter, someFunction)

I know that if I will call that function like this

wrap(v.begin(), v.end(), fill5< vector<int>::iterator> );

it will compile. But do I always have to do it explicit? It's sucks. Why compiler can't deduce which function will be used? Is there any possibility to write wrap function to take arguments like in the first one?

In C++03 or C++11 there isn't much you can do about it.

fill5 is a function template , and you cannot take the address of a function template. A function template is regarded by the compiler as an infinite overload set, and requires you to specify explicitly which instance you want to take the address of:

wrap(v.begin(), v.end(), fill5<vector<int>::iterator>);
//                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Alternatively (as I mentioned in a comment to the original post, and as other answers suggest) you could use a functor with a templated call operator to wrap the invocation of fill5 .

In C++14, however, we can do something better: we can use generic lambdas to simplify things a bit. If you define this macro:

#define WRAP(f) \
    [&] (auto&&... args) -> decltype(auto) \
    { return f (std::forward<decltype(args)>(args)...); }

You can then write:

int main()
{
    std::vector<int> v(100, -1);
    wrap(v.begin(), v.end(), WRAP(fill5));
}

Here is a live example .

An alternative is to use a functor:

class fill5
{
public:
    template <typename Iter>
    void operator () (Iter first, Iter last) const
    {
        std::fill(first, last, 5); 
    }
};

int main( int, char ** )
{
    std::vector<int> v(100, -1);

    wrap(v.begin(), v.end(), fill5);
    return 0;
}

Because fill is a template function, there are basically an infinite number of overloads and the compiler does not know which one to choose.

If you declared your second template parameter to describe a function that took 2 parameters of type Iter it could then deduce it. The example below works and looks like what you want. It is not quite as generic as your attempt. It ensures the function to be called returns void and takes 2 Iter paramters.

template <typename Iter >
void wrap( Iter first, Iter last, void(*someFunction)(Iter,Iter) )
{
someFunction( first, last );
}

template <typename Iter>
void fill5(Iter first, Iter last)
{
    fill(first, last, 5); 
}

int main( int, char ** )
{
std::vector<int> v(100, -1);
wrap(v.begin(), v.end(), fill5);

return( 0 );
}

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