8

I've got a question about how to properly use the new C++11 std::function variable. I've seen several examples from searching the Internet, but they don't seem to cover the usage case I'm considering. Take this minimum example, where the function fdiff is an implementation of the finite forward differencing algorithm defined in numerical.hxx (which isn't the problem, I just wanted to give a contextual reason why I'd want to take an arbitrary function and pass it around).

#include <functional>
#include <iostream>
#include <cmath>
#include "numerical.hxx"

int main()
{
    double start = 0.785398163;
    double step  = 0.1;
    int    order = 2;

    std::function<double(double)> f_sin = std::sin;

    std::cout << fdiff(start, step, order, f_sin) << std::endl;

    return 0;
}

Attempting to compile the above program gives me the error (in clang++)

test.cpp:11:32: error: no viable conversion from '<overloaded function type>' to
      'std::function<double (double)>'
        std::function<double(double)> f_sin = std::sin;
                                      ^       ~~~~~~~~
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/functional:2048:7: note: 
      candidate constructor not viable: no overload of 'sin' matching
      'nullptr_t' for 1st argument
      function(nullptr_t) noexcept
      ^
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/functional:2059:7: note: 
      candidate constructor not viable: no overload of 'sin' matching 'const
      std::function<double (double)> &' for 1st argument
      function(const function& __x);
      ^
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/functional:2068:7: note: 
      candidate constructor not viable: no overload of 'sin' matching
      'std::function<double (double)> &&' for 1st argument
      function(function&& __x) : _Function_base()
      ^
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/functional:2092:2: note: 
      candidate template ignored: couldn't infer template argument '_Functor'
        function(_Functor __f,
        ^
1 error generated.

or from g++

test.cpp: In function ‘int main()’:
test.cpp:11:45: error: conversion from ‘<unresolved overloaded function type>’ to non-scalar type ‘std::function<double(double)>’ requested

As I understand the problem, it's because std::sin is implemented as a template class in the standard library, but I can't seem to figure out what I need to do to give enough of a specialization to get a function reference. I've also tried various things like using the new auto keyword, using &std::sin to get a pointer, etc., but they all give me the same type of error.

jmert
  • 183
  • 1
  • 3

2 Answers2

16

std::sin is an overloaded function: you must disambiguate which std::sin overload you mean:

std::function<double(double)> f_sin = (double(*)(double))&std::sin;

There are some cases where the compiler can disambiguate overloaded functions (e.g., if f_sin was of type double(*)(double), the cast would not be required). However, this is not one of those cases.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • 1
    `std::function` providing a `Sig*` or `Sig&` constructor overload would help, too. – Luc Danton Sep 19 '12 at 18:19
  • 1
    Thanks. This does work (though sort of messily IMO) if I remove the first inner set of parentheses to have `(double(*)(double))&std::sin`. – jmert Sep 19 '12 at 18:21
  • Yes, those parentheses were extraneous and I've edited the answer to remove them. – James McNellis Sep 19 '12 at 18:22
  • 1
    As a follow up question, I guess, is where is the advantage of `std::function` over using C-style function pointers if the "C++-way" can't resolve overloads while the "C-way" can? I know that if I use `double (*func)(double)` in my definition of `fdiff` instead, I don't need an explicit cast when using `std::sin` as an argument while apparently I will need a cast if I define `fdiff` using `std::function`. – jmert Sep 19 '12 at 18:27
  • 2
    `std::function` supports arbitrary callable object types (e.g. it works with the result of a call to `std::bind`, a functor, or a stateful lambda). Function pointers support none of these. – James McNellis Sep 19 '12 at 18:30
  • OK. I guess a nice piece of 'syntax-candy' would have been for the `std::function` declaration to be capable of resolving overloads as well. But now I know, and hopefully this question will help answer questions for others in the future (since I never came across something like this in my Google searching). – jmert Sep 19 '12 at 18:33
  • @jmert The typical way to avoid the double type definition is to use something like [`make_function`](http://stackoverflow.com/questions/27825559/why-is-there-no-stdmake-function), where specifying the type can be omitted if it can be deducted from the argument. – nwp May 22 '15 at 11:05
2

With lambda you will be always on safe side:

std::function<double(double)> f_sin = [](double arg) -> double { return std::sin(arg); };

Actually you can do better, if you can change fdiff or it is already accepting template parameter - not just std::function<double(double)>:

auto f_sin = [](double arg) -> double { return std::sin(arg); };
std::cout << fdiff(start, step, order, f_sin) << std::endl;

[UPDATE] This answer is new version, previous advice to use function template specialization was incorrect, since std::sin is not function template but set of overloaded functions.

PiotrNycz
  • 23,099
  • 7
  • 66
  • 112
  • I still get the same error message as I reported above with that change (this was one of the variations I have tried). – jmert Sep 19 '12 at 18:10
  • I was misleading by OP by: `"std::sin is implemented as a template class in the standard library"` ;) @JamesMcNellis of course your answer is then valid, – PiotrNycz Sep 19 '12 at 18:17
  • Sorry about the poor wording. I meant a template function, and this was based on looking at line 455 of the cmath header I have on my computer (g++ 4.7.1). Am I reading the header file incorrectly and it's not actually a template function? – jmert Sep 19 '12 at 18:20
  • @jmert No problem. A side note is that the right name is `function template` not `template function`. Same for `class template`, – PiotrNycz Sep 19 '12 at 18:22
  • I was incorrect... additional `sin` overloads were added in C++11... I've retracted all incorrect comments. Sorry about that. – James McNellis Sep 19 '12 at 18:29