Type inference when passing overloaded functions

From page 104 of Accelerated C++:
There is a function call
find_if(i, str.end(), g)
The function g is supposed to be applied to elements indexed by the iterator i.
The authors say that passing an overloaded function to template functions is problematic as the compiler cant figure out the precise function.
But, we want the function g which can be applied to elements indexed by i --- this seems like simple enough type inference; why cant the compiler do this?
That's because of the prototype
1
2
template< class Iterator, class Function >
Iterator find_if( Iterator begin, Iterator end, Function f);

That allows for 'f' to be anything (a function, but also an object that has overloaded operator() )

I guess that you could provide an overload for functions.
Hmm, the book seemed to imply that the problem was not because of function-object confusion, but purely due to overloaded functions.

Eg, suppose we do not have any objects named g in my example, just two overloaded versions of the function g, say one that takes char and another that takes wchar_t. The book says this would be a problem.
In order to not be ambiguous the function should be declared as
1
2
3
4
5
6
template<class Iterator>
Iterator find_if(
  Iterator begin,
  Iterator end,
  bool (*f) (typename std::iterator_traits<Iterator>::value_type) //the type of *begin
); 
But that will not allow any other functions.
By instance, islower() receives an int so you couldn't use it with a string (that stores char)
Neither you could use an object with operator()

I'm not saying that there is an object with that name. What I'm saying is that there is no type information.
The template parameter could be anything, so the compiler can't decide, as all overloads are equally valid.
Last edited on
Thanks ne555. I think I understand now the complexities involved.

One question:

Why is this true:
By instance, islower() receives an int so you couldn't use it with a string (that stores char)


islower() is meant to be used with char so I am a bit confused.
islower() is part of the C library. In C, 'c' is an int.
islower() is part of the C library. In C, 'c' is an int.


So islower() should be able to be used with strings thats store chars, contradicting what ne555 said?
You misunderstood me.
If the prototype were
1
2
3
4
5
6
7
8
namespace test{
  template<class Iterator>
    Iterator find_if(
    Iterator begin,
    Iterator end,
    bool (*f) (typename std::iterator_traits<Iterator>::value_type) //the type of *begin
  );
}

You could not do
1
2
std::string s;
test::find_if(s.begin(), s.end(), std::islower);
error: no matches converting function ‘islower’ to type ‘bool (*)(char)’
/usr/include/ctype.h:116:1: error: candidates are: int islower(int)


If the prototype were
1
2
3
4
5
6
  template<class Iterator, class Function>
    Iterator find_if(
    Iterator begin,
    Iterator end,
    Function f
  );
Then you could do find_if(s.begin(), s.end(), (int(*)(int))std::islower); (the casting ¿selection? is necessary because there are overloads of the function)

In C, 'c' is an int
¿are you sure? I don't know how to test that.
man wrote:
These functions check whether c, which must have the value of an unsigned char or EOF, falls into a certain character class according to the current locale.
I guess it ask for an int because of EOF.
Last edited on
ne555 thanks.

if the prototype were
1
2
3
4
5
6
7
8
namespace test{
  template<class Iterator>
    Iterator find_if(
    Iterator begin,
    Iterator end,
    int (*f) (typename std::iterator_traits<Iterator>::value_type) //the type of *begin
  );
}


Would this work?:
1
2
std::string s;
test::find_if(s.begin(), s.end(), std::islower);


ie, can I use a function of type int (*)(int) when the declared type is int (*)(char)?
I would think so, because passing chars to a function which accepts is ok?
Last edited on
Topic archived. No new replies allowed.