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.
Related
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.
Let's consider:
void goo () {
std::cout << "void goo ()\n";
}
int goo (int) {
std::cout << "int goo (int)\n";
return 42;
}
And now I want to call one of those functions using some wrapper function defined like this:
template <typename F, typename... A>
void c (F&& f, A&&... a) {
f (std::forward<A> (a)...);
}
With usage:
c (&goo, 10); // (X)
c (&goo); // (Y)
Both cases fail (GCC 5.3.1) with appropriate errors:
error: no matching function for call to ‘c(<unresolved overloaded function type>, int)’
error: no matching function for call to ‘c(<unresolved overloaded function type>)’
As far as I am concerned the fail is because compiler could not choose appropriate overload when it has to initialize f object (too few information).
As a solution of course I can write usage calls like this:
c (static_cast<int (*) (int)> (&goo), 10);
c (static_cast<void (*) ()> (&goo));
To tell the compiler which pointer I really want to use.
Writing this static_cast for me makes code much more uglier, so I wrote a wrapper function for converting function pointer to appropriate one using template:
template <typename R, typename... Args>
using Funptr_t = R (*) (Args...);
template <typename R, typename... Args>
Funptr_t<R, Args...> funptr (Funptr_t<R, Args...> ptr) {
return static_cast<Funptr_t<R, Args...>> (ptr);
}
and now usage looks much better:
c (funptr<int, int> (&goo), 10);
c (funptr<void> (&goo));
My question is: Do you have any better idea how to deal with that kind of situation? I am pretty sure this happen very often in generic code. So, please advice me something.
The ideal solution would be if I could use (X) and (Y) directly, so the magic trick with pointing appropriate overload would be done using A... and hidden to the caller.
I mean, you can always specify the template parameter explicitly:
c<int(int)>(&goo, 10);
c<void()>(&goo);
AFAIK there is no way to do that in c, because F cannot be deduced (ambiguity between the overloads), and to make the compiler deduce the correct type, you need to change something on the caller side.
If C++14 is available, then generic lambdas offer a solution to the "passing overload sets as function arguments" problem:
#define FWD(arg) static_cast<decltype(arg)&&>(arg)
auto goo_fn = [](auto&&... args) -> decltype(goo(FWD(args)...)) {
return goo(FWD(args)...);
};
c(goo_fn, 10); // ok
c(goo_fn); // ok
goo_fn is a lambda that transparently (as much as possible anyway) represents the overload set of goo. The trailing decltype is necessary for two reasons: (1) to ensure that the return type is a reference if that overload of goo's is and (2) to ensure SFINAE-friendliness (which decltype(auto) would not.
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.
I have a very strange problem. To keep things simple, lets say I want to have a function which takes 2 functions with the same declaration as arguments
template<typename Func>
void foo(Func a, Func b)
{
std::cout << "good";
}
To try things out I took putchar from cstdio, and created an identical function to match the putchar.
int myPutcharFunc(int)
{
return 0;
}
int main()
{
auto myPutcharLambda = [](int) -> int
{
return 0;
};
foo(putchar, myPutcharFunc); // okay
foo(putchar, myPutcharLambda); //deduced conflicting types for parameter 'Func' ('int (__attribute__((__cdecl__)) *)(int)' and 'main()::<lambda(int)>')
}
Now, the lambda does not want to compile (the key is I want to use lambda capture).
So lets add template specialization, because the programmer is wiser than the machine, right? :)
template<typename Func>
void foo(Func a, Func b)
{
std::cout << "good";
}
template<>
void foo(int(*)(int), int(*)(int))
{
std::cout << "good";
}
No luck, the same error - why?
But for some reason, when I comment out the template specialization:
//template<>
void foo(int(*)(int), int(*)(int))
{
std::cout << "good";
}
The code compiles. I obviously do not want to overload foo for EVERY set of function's arguments - thats what templates are for. Every step was tested both with msvc++ and g++. What am I doing wrong?
Two possibilities.
1: Just put + in front of the lambda:
foo(putchar, +myPutcharLambda);
That works because unary + expects an integer-like value, such as a pointer. Therefore, the lambda converts to a function pointer.
Ultimately a (non-capturing) lambda doesn't have the same type as a function pointer, even though it's willing to convert to a function pointer.
How is a compiler supposed to know which conversions are allowed to make two objects of the same type?
2: There is another option, making use of the fact that the ?: is willing to do some conversions, converting one type to another in some circumstances.
template<typename Func1, typename Func2>
void foo2(Func1 a, Func2 b)
{
using common_type = decltype(true?a:b); // or 'false', it doesn't matter
foo<common_type>(a,b);
}
Every lambda is a different type, so you'll need to have two different template parameters to get them
template<typename FuncA, typename FuncB>
void foo(FuncA a, FuncB b)
Types don't decay when deducing template types (SEE COMMENT FOR CORRECTION). So a lambda remains a lambda and doesn't decay to a function pointer. Same reason a string literal is deduced as a char[N] instead of a const char *.
With your second example using specialization, it doesn't want to use your specialization, since the lambda is not a function pointer. You can cast the Lambda to a function pointer and make it work: https://godbolt.org/g/ISgPci The trick you can do here is say +my_lambda because + is defined for pointers so it will force the non-capturing lambda to become a function pointer.
A lambda has its own type which can decay to a function pointer but not in the case of a template function match, it will for the real function as you found because of the implicit conversion.
In the case of matching to a template you need to disambiguate and explicitly instantiate foo with the type you want or convert the lambda to a function pointer.
foo<decltype(putchar)>(putchar, myPutcharLambda);
or
foo(putchar, +myPutcharLambda);
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