Compare of std::function with lambda - c++

How to compare of std::function with lambda?
#include <iostream>
#include <functional>
using namespace std;
int main()
{
using Type = void( float, int );
std::function<Type> a;
auto callback = []( float d, int r )
{
cout << d << " " << r << endl;
};
static_assert( std::is_same< Type , decltype( callback ) >::value, "Callbacks should be same!" );
a(15.7f, 15);
}
Because in case of first parametr of lambda would be int - code would compile with 1 warning. How to protect code?

The type of the callback is not a simple function. A lambda with no captures can decay to function pointer but it isn't a function pointer. It's an instance of a local class.
If you want to ensure a specific function type for a lambda, you can do that by forcing the decay to function pointer type:
#include <iostream>
#include <functional>
using namespace std;
int main()
{
using Type = void( float, int );
std::function<Type> a;
auto callback = []( float d, int r )
{
cout << d << " " << r << endl;
};
// Ensures desired type.
{
Type* const func_ptr = callback; (void) func_ptr;
}
a = callback;
a(15.7f, 15);
}

Related

Why is this C++ code which uses decltype and remove_reference with the goal of getting the value type of a pointer working unexpectedly

When I run the snippet below, it prints out:
int&
int __cdecl(void)
I was expecting the second line to just be int
Why is this happening? What could I do to fix it if it were inside a templated function that takes pointers or iterators so I couldn't use std::remove_pointer.
#include <type_traits>
#include <iostream>
int main()
{
int r = 4;
int* rp = &r;
using return_type = decltype(*rp);
using no_ref_type = std::remove_reference<return_type>::type();
std::cout << typeid(return_type).name() << '&' << std::endl;
std::cout << typeid(no_ref_type).name();
}

why can't I convert a lambda to a std::function here?

I need a function that generates other functions. Why doesn't the following not let me convert a lambda to a std::function? I've done that before.
#include <iostream>
#include <functional>
std::function<int()> funcGen(int param) {
std::function<int()> myGeneratedFunc =
[param](int input) -> int {
return input+param;
};
return myGeneratedFunc;
}
int main() {
std::function<int()> myFunc = funcGen(3);
std::cout << "this should be 4=3+1: " << myFunc(1) << "\n";
return 0;
}
On ideone I get the following error:
error: conversion from ‘funcGen(int)::<lambda(int)>’ to non-scalar type ‘std::function<int()>’ requested
std::function<int()> accepts a function which takes in no arguments and returns an int. Your proposed lambda takes in an int and returns an int.
Consider std::function<int(int)> instead:
#include <iostream>
#include <functional>
std::function<int(int)> funcGen(int param) {
std::function<int(int)> myGeneratedFunc =
[param](int input) -> int {
return input+param;
};
return myGeneratedFunc;
}
int main() {
std::function<int(int)> myFunc = funcGen(3);
std::cout << "this should be 4=3+1: " << myFunc(1) << "\n";
return 0;
}

Expand variadic arguments in initializer list fails

I try to create a simple program in which I want to create vector of future arguments.
I created a wrapper function which is used to submit lambda functions and stores internally in a vector the future objects
I use an intermediate step in which I create an initiliazer_list using variadic arguments . But fails to compile. I try to use to call a function in order to push the elements in the vector and fails to compile as well
Below is the code
#include <iostream>
#include <thread>
#include <future>
#include <functional>
#include <cstdlib>
#include <chrono>
#include <initializer_list>
using namespace std;
using FunctPtr = function<int(int, int) >;
using FutureInt = future<int>;
using AsyncVector = vector<FutureInt>;
AsyncVector asyncVec;
template<typename... TemplatePtr>
void submit(TemplatePtr... pFunc)
{
auto initList {pFunc... };
for (auto & element : initList)
{
asyncVec.emplace_back(async(launch::async, element,4,5));
}
}
int main()
{
int a;
int b;
auto addPtr = [](int x, int y)->int
{
std::cout << "add :" << x + y << std::endl;
return x + y;
};
auto multPtr = [](int x, int y)->int
{
std::cout << "mult :" << x * y << std::endl;
return x * y;
};
// submit(add,4,5);
submit(addPtr, multPtr);
for (auto & v : asyncVec)
{
std::cout << "Wait for " << v.get() << std::endl;
}
}
Yes, they are of different types so cannot be in the same init-list easily.
Your best options should probably be:
Either push them all into asyncVec in the same fold-expression.
template<typename... TemplatePtr>
void submit(TemplatePtr... pFunc)
{
(asyncVec.emplace_back(async(launch::async, std::move(pFunc), 4, 5)), ...);
}
Or, if they all are of the same signature, type-erase them, like keeping them in an array of std::function.
template<typename... TemplatePtr>
void submit(TemplatePtr... pFunc)
{
for (auto &&element: {std::function<int(int, int)>(std::move(pFunc))...})
{
asyncVec.emplace_back(async(launch::async, std::move(element), 4, 5));
}
}
(I have specified function signature explicitly though compiler should be able to deduce it.)
Or, if all closures are captureless and of the same signature, simply cast them to the same type when calling submit:
using SameType = int (*)(int, int);
submit(static_cast<SameType>(addPtr), static_cast<SameType>(mulPtr));
This way your original submit should work as is.

Mapping Strings to Functions with Different Return Types

I've seen variants of this question asked, but they usually involve functions returning the same type. Here is my code:
#include <iostream>
#include <functional>
#include <map>
using namespace std;
void checkType(int x){
cout << "we got an int: " << x << endl;
}
void checkType(float x){
cout << "we got a float: " << x << endl;
}
int getInt(){
return 1;
}
float getFloat(){
return -101.23f;
}
int main(){
map<string, function<float()> > myMap({
{"int", getInt},
{"float", getFloat}
});
checkType(myMap["int"]());
checkType(myMap["float"]());
return 1;
}
The goal here is to call different versions of an overloaded function (checkType) depending on what the mapped function returns. Obviously the checkType(float) function ends up getting called twice because my map thinks all its functions return floats.
Is there a good way to do this? And is it at all good practice? I've found a different solution, but I think if something like this is legitimate it could be pretty sexy.
As you already found out, the way you implemented it, is not going to work, since the functions stored in map are returning float.
A proper way is to use type erasure, but if you use void* you have to take care of proper casting. Another option is to use boost::any, or QVariant.
This example uses const void* to erase types :
#include <iostream>
#include <functional>
#include <map>
using namespace std;
void callForInt(const void* x){
const int* realX = static_cast < const int* >( x );
cout << "we got an int: " << *realX << endl;
}
void callForFloat(const void* x){
const float* realX = static_cast < const float* >( x );
cout << "we got a float: " << *realX << endl;
}
int main(){
map<string, function<void(const void*)> > myMap({
{"int", callForInt},
{"float", callForFloat}
});
const int v1 = 1;
const float v2 = -101.23f;
myMap["int"](&v1);
myMap["float"](&v2);
}

Is there a way to deduce the signature of a lambda as an mpl sequence?

Is there a way to deduce the signature, result- and parameter-types, of a c++0x lambda as a Boost.MPL sequence, for example a boost::mpl::vector? For example, for a lambda
[]( float a, int b ) -> void { std::cout << a << b << std::endl; }
I would like to get a boost::mpl::vector<void,float,int>.
C++0x lambdas which are "closure-objects" are functors. So you can use boost.Boost.FunctionTypes to decompose its operator().
Example:
#include <boost/function_types/parameter_types.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/int.hpp>
int main()
{
int x = 1;
auto f = [x](char a, short b, int c){ return x; };
typedef decltype(f) lambda_t;
typedef boost::function_types::parameter_types<
decltype(&lambda_t::operator())>::type args_t;
// we can use boost::mpl::identity<decltype(f)>::type instead of lambda_t
static_assert(sizeof(boost::mpl::at<args_t, boost::mpl::int_<1>>::type) == 1, "");
}