2
votes

I got a (simplified) function Foo

template<typename It, typename T>
void Foo(It begin, It end, T&& CallBar)
{
    CallBar(begin, end);
}

And another simplified function Bar

template<typename It>
It Bar(It begin, It end)
{
    return begin;
}

When I call both functions in the following way

std::vector<int> v{ 3, 8, 2, 5, 1, 4, 7, 6 };
Foo(v.begin(), v.end(), Bar);

I get the error

'declaration' : could not deduce template argument for 'identifier'

What else do I have to specify to make it compile?

3
@NathanOliver: Its a bit difficult in this case, since I am using the Test facilites of VS2017 to run the last code snippet. - user1934212
You can use generalized lambdas to avoid having to specify the template argument in Bar : Foo(v.begin(), v.end(), [](auto begin, auto end) {return begin;}); - maxbc

3 Answers

6
votes

The issue here is that since Bar is a function template, it does not know which Bar you want. You have to tell it what version of Bar to use. One way to do that is by specifying the template type. You can do that like:

Foo(v.begin(), v.end(), Bar<decltype(v.begin())>);

If you would like to not have to specify the template type, which to be honest, is a little brittle then we can wrap the call to Bar in a lambda. This will allow the compiler to do all of the type deduction for us which is a lot easier to maintain. For example if you change the iterator type nothing you neede to be changed unlie the previous solution. Thanks to 0x499602D2 that would be

Foo(v.begin(),v.end(),[](auto b,auto e){return Bar(b,e);})
2
votes

What else do I have to specify to make it compile?

By example

template<typename It>
void Foo(It begin, It end, It(* CallBar)(It, It))
{
    CallBar(begin, end);
}
2
votes

You can use template templates to help solve this. As far as I know, it requires you to wrap your Bar function in a functor. By placing the functor template parameter first, you can specify it and let the iterator type be deduced.

#include <vector>

// T is a type that takes a 'class' template argument
template<template<class> class T, class It>
void Foo(It begin, It end)
{
    T<It>()(begin, end);
}

template<typename It>
struct Bar
{
    It operator()(It begin, It end)
    {
        return begin;
    }
};

int main()
{
    std::vector<int> v{ 3, 8, 2, 5, 1, 4, 7, 6 };
    Foo<Bar>(v.begin(), v.end());
    return 0;
}