9

So in it's most distilled form I have something like this going on,

template <class T>
bool f(const T &a, const T &b, std::function<bool(const T&, const T&)> func)
{
    return func(a,b);
}

template <class T>
bool g(const T &a, const T &b)
{
    return true;
}  

But any attempt to call f(), with anything, f('a', 'b', g), f(1, 2, g), always results in "no matching function for call to 'f'", regardless of whether I pass the variables as const references or just plain values or whatever. I'm assuming it's failing to deduce some template, but I have no idea where or why.

I will admit, I have a very tenuous grasp on how to use function objects in general, is doing something like this even possible?

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
Arii
  • 349
  • 2
  • 10

2 Answers2

7

The parameter func is declared as std::function, and you're trying to pass a function pointer, which requires implicit conversion. Template argument deduction doesn't consider implicit conversion and then deduction fails.

Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.

You can construct an std::function explicitly,

f('a', 'b', static_cast<std::function<bool(const char&, const char&)>>(g<char>));

Or specify the template argument explicitly (to bypass template argument deduction and make implicit conversion taking effect later),

f<char>('a', 'b', g<char>);    

Or just don't use std::function.

template <class T, class F>
bool f(const T &a, const T &b, F func)
{
    return func(a,b);
}

f('a', 'b', g<char>);
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • Yeah, that's how I had it set up before trying to work with std::function. So... what happens when I give it a pointer to a function that doesn't return a bool? Is that just undefined behaviour to be wary of? – Arii Sep 26 '18 at 01:45
  • No, like, if I have a templated function `int f(int a, int b, F func)` that does nothing but return the result of `func`, and I pass it a function that returns a `char`, what happens? – Arii Sep 26 '18 at 02:36
  • @Arii `char` will be converted to `bool` and returned. If the function passed returns sth that can't be converted to `bool` then you'll get a complication error. – songyuanyao Sep 26 '18 at 02:44
  • @Desperado17 No. For the same reason, the implicit conversion from lambda to `std::function` won't be considered in template argument deduction. – songyuanyao Feb 26 '21 at 14:05
  • @songyuanyao For clarification: The lambda is not templated. Only the function that takes the std::function parameter the lambda is passed to is. Will that change your statement? – Desperado17 Feb 26 '21 at 14:18
  • @Desperado17 Like [this code](https://wandbox.org/permlink/OX9n4EhULTdyaSVl)? No, it won't work. – songyuanyao Feb 26 '21 at 14:21
  • @songyuanyao I have a deleter function for a templated object class that I'd like to define in the constructor call of the templated object class and store it inside the object. Contrary to my previous statement one of the parameters of the deleter function is, in fact, of the internal type that is passed as template argument to the object class. Does c++11 feature an elegant way to achieve this? – Desperado17 Feb 26 '21 at 14:33
  • @Desperado17 Could you make a minimal reproducible sample? And might be better to post it as question. – songyuanyao Feb 26 '21 at 14:42
1

I've fixed this up a bit for you and added some examples. This should help you to understand how to use a simple std::function.

#include <iostream>
#include <string>
#include <functional>

template <class T>
bool f(const T &a, const T &b, std::function<bool(const T&, const T&)> func)
{
    return func(a,b);
}

template <class T>
bool g(const T &a, const T &b)
{
    return a==b; // a simple comparator
}  

int main()
{
   int a = 1;
   int b = 1;

   // instantiate f and g as integer type functions
   if( f<int>(a,b,g<int>) == true) 
      std::cout << "true" << std::endl;
   else
      std::cout << "false" << std::endl;

   std::string c="dead";
   std::string d="beef";
   // and now as strings
   if( f<std::string>(c,d,g<std::string>) == true) 
      std::cout << "true" << std::endl;
   else
      std::cout << "false" << std::endl;
   return 0;
}
Matthew Fisher
  • 2,258
  • 2
  • 14
  • 23
  • Yes, that's more informative than anything else I've found, thank you. Question, why can't the type of f be inferred from g? – Arii Sep 26 '18 at 01:37