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.
Instances of std::function can store, copy, and invoke any CopyConstructible Callable target -- functions (via pointers thereto), lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members.
They are not the same at all. std::function is a complex, heavy, stateful, near-magic type that can hold any sort of callable entity, while a function pointer is really just a simple pointer. If you can get away with it, you should prefer either naked function pointers or auto - bind / auto -lambda types.
std::function is a type erasure object. That means it erases the details of how some operations happen, and provides a uniform run time interface to them. For std::function , the primary1 operations are copy/move, destruction, and 'invocation' with operator() -- the 'function like call operator'.
std::function can hold more than function pointers, namely functors. Live example on Ideone. As the example shows, you also don't need the exact same signature, as long as they are compatible (i.e., the parameter type of std::function can be passed to the contained function / functor).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With