C++11 - std::function, templates and function objects, weird issues - c++

I'm playing with some code and I am a little puzzled about some stuff. Here's a simplified example:
I have Nodes that perform arithmetical operations (addition, subtraction, etc). I have a container with the different operations that are available in my program. Here's an example:
typedef std::binary_function<double, std::vector<double>&, std::vector<Node*>& > my_binary_function;
auto const & product = [](double v, Node* n){ return v * n->GetEvaluation(); };
struct addition : public my_binary_function {
double
operator()(std::vector<double>& weights, std::vector<Node*>& subtrees) {
return std::inner_product(weights.begin(), weights.end(),
subtrees.begin(), 0, std::plus<double>(), product);
}
};
Now, at this point there are two choices:
1) use a function type:
typedef double (*my_function)(std::vector<double>&, std::vector<Node*>&);
Then use the following templated function to convert the functors:
template<typename F> typename F::result_type
func(typename F::first_argument_type arg1, typename F::second_argument_type arg2) {
return F()(arg1, arg2);
}
2) use a function wrapper type, namely std::function, so that I have
typedef std::function<double (std::vector<double>&, std::vector<Node*>&)> my_function;
It all boils down to something like this:
LoadDefaultFunctions() {
int minArity = 2;
int maxArity = 2;
function_set_.AddFunction("Add", func<addition> , minArity, maxArity, 1.0); // case 1
OR
function_set_.AddFunction("Add", addition(), minArity, maxArity, 1.0); // case 2
And now the problems:
a) If I use Method 1, I get this compilation error:
error: invalid initialization of non-const reference of type
'std::binary_function<double, std::vector<double>&,
std::vector<Node*>&>::result_type {aka std::vector<Node*>&}'
from an rvalue of type 'double'
The error goes away if I change the template (notice how the arguments don't really make sense now):
template <typename F> typename F::first_argument_type
func1(typename F::second_argument_type arg1, typename F::result_type arg2) {
return F()(arg1, arg2);
}
I find it very strange, because for other types such as binary_op<double, double, double>, the first form works fine. So, what's happening?
b) 1) is faster than 2) (by a small margin). I'm thinking I'm probably missing some neat trick of passing the functor by reference or in some way that would enable std::function to wrap it more efficiently. Any ideas?
c) If I use the typedef from 2) but additionally I still use func to produce a function out of the functor, and let std::function deal with it, it's still faster than 2). That is:
`my_function = func<addition>` is faster than `my_function = addition()`
I would really appreciate it if someone could help me understand the mechanics behind all of this.
Thanks.

b) 1) is faster than 2) (by a small margin). I'm thinking I'm probably missing some neat trick of passing the functor by reference or in some way that would enable std::function to wrap it more efficiently. Any ideas?
Yes, I would expect 1 to be faster than 2. std::function performs type-erasure (the exact type of the stored callable is not present in the enclosing std::function type) which requires the use of a virtual function call. On the other hand, when you use a template, the exact type is known, and the compiler has greater chances of inlining the calls, making it a no-cost solution. This is not related to how you pass the functor.
The error
The order of the template arguments is incorrect:
typedef std::binary_function<double, // arg1
std::vector<double>&, // arg2
std::vector<Node*>& // return type
> my_binary_function;
struct addition : public my_binary_function {
double // return type
operator()( std::vector<double>& weights, // arg1
std::vector<Node*>& subtrees) // arg2
{ ...
That is, inheritance from binary_function is adding some typedefs to your class, but those are not the correct typedefs. Then when you use the typedefs in the next template, the types don't match. The template is expecting that your operator() will return a std::vector<Node*>&, and that is the return type of func, but when you call the functor what you get is a double which leads to the error:
invalid initialization of ... std::vector<Node*>& from double

Related

c++ template parameter compiler can not deduce

here is function to register.
template <typename ReqT, typename RespT>
bool RegisterCmdHandler(int cmd_id, std::function<int(int, const ReqT&, RespT&)> sync_handler) {
// ... do something with sync_handler and register it for later callback
return true;
}
and a specific handler to register:
int SomeHandler(int id, const Foo& req, Bar& resp) {
// ... specific logic
}
now I want to apply the Handler to Register Function, compiler complains
RegisterCmdHandler(1, SomeHandler); // ERROR, compiler can not deduce
while specificly write out the type is OK:
RegisterCmdHandler<Foo, Bar>(1, SomeHandler); // OK, compiler can deduce
but the latter has ugly API. How can I get the first on work?
How can I get the first on work?
Add an overload for plain function pointers:
template <typename ReqT, typename RespT>
bool RegisterCmdHandler(int cmd_id, int(*sync_handler)(int, const ReqT&, RespT&)) {
std::function<int(int, const ReqT&, RespT&)> sync_handler2(sync_handler);
return RegisterCmdHandler(cmd_id, sync_handler2);
}
How can I get the first on work?
I see some ways.
(1) If you can modify the RegisterCmdHandler() function and you don't need to know, inside it, what types ReqT and RestT are, I suggest you to avoid at all std::function and accept sync_handler as a simple template type.
I mean
template <typename F>
bool RegisterCmdHandler (int cmd_id, F sync_handler) {
// ... do something with sync_handler
return true;
}
This is a very flexible solution because F can be a function, a function pointer, a std::function, a lambda (also a generic lambda, so this solution is more flexible than using std::function), another type of class/struct with an operator(), a value returned from a std::bind. In short: a generic callable.
(2) If you can modify the RegisterCmdHandler() function but you need to know (and use) the ReqT and RestT, you can follows the plain function pointer way (see Maxim Egorushkin's answer for the syntax). Unfortunately this works with function pointers only and doesn't works (by example) when sync_handler is a lambda.
(3) If you can't modify RegisterCmdHandler() but you can use C++17, you can use std::function deduction guides and call the function as follows
RegisterCmdHandler(1, std::function{SomeHandler});
or, maybe better if you have to call it in different places, call it through a converter
template <typename F>
auto CallRegisterCH (int cmd_if, F && func)
{ return RegisterCmdHandler(cmd_if, std::function{std::forward<F>(func)}); }
calling it as follows
CallRegisterCH(1, SomeHandler);
(4) if you can't modify RegisterCmdHandler() and you have to use C++11 or C++14... well... explicating the template types
RegisterCmdHandler<Foo, Bar>(1, SomeHandler);
seems to me the better way.
Other ways you can explicit the std::function
std::function<int(int, Foo const &, Bar &)> sh{ SomeHandler };
RegisterCmdHandler(1, sh);
but seems to me almost the same thing.

Why could not deduce template argument when passing lambda instead of function pointer

I have a bubble-sort function that takes an array, a compare function, and a boolean that indicates if it should sorts the array upside-down. It is a template function that supports any data-type, and will deduce array size automatically.
When specifying the compare function, if I pass function pointer, the compiler will deduce the data type of array automatically, which is great. But if I pass a lambda instead, it will not deduce automatically. I have to specify the data type explicitly, or static_cast the lambda as fnCompare_t<double>.
What is the reason behind this? Because according to this post, as long as the lambda doesn't capture, it can be used like the plain-old function pointer, but it seems it is not always the case? How come it can be different in this case?
#include <iostream>
using namespace std;
template <typename T>
using fnCompare_t = int(*)(T const &, T const &);
template <typename T, size_t count>
inline void BubbleSort(
T(&array)[count],
fnCompare_t<T> fnCompare,
bool reverse)
{
cout << "TODO: Implement BubbleSort" << endl;
}
double doubleArray[] = {
22.3, 11.2, 33.21, 44.2, 91.2, 15.2, 77.1, 8.2
};
int CompareDouble(double const & a, double const & b)
{
return a > b ? 1 : a == b ? 0 : -1;
}
int main()
{
auto fnCompare = [](double const & a, double const & b) -> int {
return a > b ? 1 : a < b ? -1 : 0;
};
// compile OK:
BubbleSort(doubleArray, CompareDouble, false);
BubbleSort(doubleArray, static_cast<fnCompare_t<double>>(fnCompare), false);
BubbleSort<double>(doubleArray, fnCompare, false);
// compile error, could not deduce template argument:
//BubbleSort(doubleArray, fnCompare, false);
return 0;
}
The reason why is because you can't get an implicit conversion on a templated parameter when using deduction. The classic example is:
template <class T>
T min(T x, T y);
Calling this function as min(1, 3.0) will result in a failure. Because for both arguments, it tries to find a T to get a perfect match, and fails. If you specify the template parameter explicitly it can work: min<double>(1, 3.0). The same is true in your example, if you specify T explicitly it will work.
The idiomatic way to write the signature for your function is:
template <typename Iter, typename F>
inline void BubbleSort(
Iter b, Iter e,
F fnCompare,
bool reverse)
However, this discards the compile time length information. If you want to keep that, you can do:
template <typename T, size_t count, typename F>
inline void BubbleSort(
T(&array)[count],
F fnCompare,
bool reverse);
Though you should at least consider using std::array instead of a C style array which will make the signature a bit less ugly and has other benefits.
This may seem odd as we are not "verifying" the comparator having the correct signature, in the signature of our sort. But this is normal in C++, if the comparator is incorrect then it will fail at the point of usage and it will still be a compile time error. Note as well when you try to depend on a lambda implicitly converting into a function pointer, you are being unnecessarily restrictive: lambdas only convert into function pointers with identical signature. Even if the output of the lambda is implicitly convertible to the output of the function pointer, your lambda will not implicitly convert, even though the lambda can still be used!
As a final final note, it's usually better to pass functors because it's better for performance. Comparators are usually small functions and often will get inlined. But in your version, the comparator will not typically be inlined, in mine it will (because I preserve the original type of the lambda, and you do not).
You need to explicitly cast the lambda to a function pointer. There is no other way around it. But, instead of static_casting you can apply + to the lambda, which would trigger the function pointer conversion, as you can apply + to a pointer type:
BubbleSort(doubleArray, +fnCompare, false);
// ^^
// applying unary + invokes the function pointer conversion operator
The reason for why there is no implicit call to the conversion operator is that during overload resolution, the compiler will only consider templates that match perfectly (see this for more info). Because a lambda is not a function pointer, there cannot be a perfect match, and the overload is discarded.

resolve address from overloaded function std::real<float>

std::vector<std::complex<float> > c;
std::vector<float> d;
std::transform(c.begin(), c.end(), d.begin(), std::real<float>);
Why couldn't the compiler resolve the address from the overloaded function real<float>?
Which overloaded functions does the compiler mean?
Your library implementation has provided additional overloads for std::real<float>.
Why the overloads?
26.4.9 Additional overloads [cmplx.over]
1 The following function templates shall have additional overloads:
arg norm
conj proj
imag real
2 The additional overloads shall be sufficient to ensure:
If the argument has type long double, then it is effectively cast to complex<long double>.
Otherwise, if the argument has type double or an integer type, then it is effectively cast to complex<double>.
Otherwise, if the argument has type float, then it is effectively cast to complex<float>.
[...]
Solutions to problem:
You could just use a range based for ...
for (auto v : c) d.push_back(real(v));
... or pack the call to real into a functor or another function ...
struct my_caller {
template <typename T> T operator() (std::complex<T> const &c) {
return real(c);
}
};
... or use the member function ...
std::transform(c.begin(), c.end(), d.begin(), [](std::complex<T> const &c) {
return c.real();
});
IMPORTANT:
Note that you have to have enough space in the target when using transform:
std::vector<float> d (c.size());
or use a back inserter:
std::transform(c.begin(), c.end(), back_inserter(d), ...);
Otherwise you are iterating over undefined memory, yielding undefined behaviour.
§26.4.9 states that (amongst others), real shall have additional overloads, for arguments of type float, double and long double. It seems your libraray implementation made a template for these overloads, maybe like
template <typename T>
T real(T const& t)
{
return std::real(std::complex<T>{t});
}
In addition to the solutions phresnel priovided, you could explicitly tell the compiler which kind of function pointer you mean:
std::transform(c.begin(), c.end(), d.begin(), (float(*)(std::complex<float> const&))std::real<float>);
The compiler then looks for a std::real that can be converted into a function pointer of the given type and will find the correct one.
I tell you this only for completeness - I consider this explicit cast ugly and would prefer the ranged based for or transform with a lambda.

How does overloading function call work in C++?

I read that function call () can also be overloaded. http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B
What would the following mean?
It works.
template<typename T, typename Comp>
struct bind{
T v;
Comp comp;
bool operator()(const T& b){
return comp(b,v);
}
};
int main(){
bind<int, less<int> > b;
b.v = 2;
cout << b(3) << "\n";
}
It means that if you create an object of type bind<>, you can apply the function-call operator to that object.
Like this:
bind<int, std::less<int>> b;
b.v = 2;
std::cout << b(1) << "\n";
That snippet might print "true" on the standard output.
If you have a class called foo, I'm sure you understand what it means to call a member function of an object of that type:
foo f;
f.bar();
You may also understand that you can overload certain operations. For example, you could overload operator+ for foo so that you could do something like this:
foo f, g;
f + g;
Now you can also overload operator() for a class, which allows you to call it as though it were a function:
foo f;
f();
Yes, f is not a function but it is an object of class type that overloads operator(). Class types that do this are known as functors or function objects.
In the example you've given, bind is a functor. When you create an object of that type, you can call it like a function, passing it a const T& and it will return a bool back to you. The implementation of operator() actually calls the function stored in comp, passing it both the T object you passed to operator(), a, and the member object v of type T.
As it stands, it doesn't mean much of anything except "syntax error". For example:
template<T, Op>
This simply isn't allowed. For each template parameter, you need to specify whether it's a type (using class or typename) or a non-type parameter such as an int. Since the apparent intent is that both these should be type parameters, you need something like:
template <class T, class Op>
or:
template <typename T, typename Op>
For this situation, there's no difference in meaning between class and typename.
struct bind{
T v;
Leaving v uninitialized will lead to undefined behavior, so you probably don't want to allow that. You'd normally prevent it by adding a constructor that takes a T as its parameter and initializes v to that value:
bind(T const &v) : v(v) {}
When you include a constructor like this, the compiler won't automatically generate a default constructor, so it's no longer possible to create a bind object with v uninitialized -- exactly what we wanted.
Although creating the comp object:
Op comp;
is fairly harmless, it's also quite unnecessary. You could just as well do the comparison with a temporary instance created with Op(), in which case this:
bool operator()(const T& a){
return comp(a,v);
}
...would become something like this (and the Op comp; simply removed):
bool operator()(T const &a) {
return Op()(a, v);
}
Even with the corrections, I'd consider this code obsolescent. In C++98/03, it would have been useful in a situation where you needed to supply a functor to an algorithm, such as:
std::remove_copy_if(a.begin(), a.end(), bind<int,
std::back_inserter(b),
bind<int, std::less<int> >(5));
...which would copy numbers from a to b, removing those less that 5.
In C++11, however, most (if not all) uses of this bind should probably be written as lambdas instead though, so the bit above would become something like:
std::remove_copy_if(a.begin(), a.end(), bind<int,
std::back_inserter(b),
[](int x) { return x < 5; });
This is not only shorter, but (at least once you're used to it) quite a bit simpler than using std::less and bind to put together a function. It won't generally make any difference in run-time efficiency -- a lambda is basically a "shorthand" way of generating a class template, so what it generates would end up pretty similar to the code using bind.

c++ function map implementation

I have been playing around with variadic templates in the new c++ standard and came up with a map function (headers + using decs excluded):
template<typename T>
T square(T i)
{
return i * i;
}
template <typename T, typename... Ts>
const tuple<Ts...> map(const T f, const Ts...args)
{
return make_tuple(f(args)...);
}
int main(int c, char *argv[])
{
tuple<int, int> t;
int (*fp) (int) = square;
t = map(fp, 6, 8);
cout <<get<0>(t) <<endl;
cout <<get<1>(t) <<endl;
return 0;
}
Which works. As long as all the arguments are the same type for map. If I change the main to use a slightly more general form:
tuple<int, float> t;
t = map(square, 6, 8.0f);
gcc 4.4 reports:
In function ‘int main(int, char**)’:
error: no matching function for call to ‘map(<unresolved overloaded function type>, int, float)’
Any ideas how to make this work?
First, you can't pass around an unresolved function template as a pointer (or template parameter), you can only pass around instances of it. What that means is that your template's first argument is being passed as an int (*)(int) in this example, and it cannot call the float (*)(float) instantiation. I'm not sure of the best way to fix that, but anyway it's not technically what you asked about.
I don't have a compiler to test this on, but I think if you use std::function to infer the types that the function you are passing in wants, you might be able to cast the parameters to the function. Like this:
template<typename T, typename Ts...>
tuple<Ts...> map(std::function<T (T)> const &f, Ts... args) {
return make_tuple(static_cast<Ts>(f(static_cast<T>(args)))...);
}
See, I think you need to cast both the parameter (as a T) and the return type (as a Ts) for the function since it seems some implicit conversion rules are not working inside this template.
If my syntax doesn't work (it probably doesn't, the ...s are tricky when you don't have a compiler for them), it might be possible that you could rewrite this as a much more verbose function which unpacks each Ts before calling the function, and then builds up a tuple as it goes. I'm not sure if that is really necessary, but my feeling is that compiler support for all of the ... unpacking is a little spotty right now, so even if you come up with something that should work, I wouldn't be surprised if your compiler couldn't handle it.