How can I use a std::function in a function which expects a C-style callback?
If this is not possible, what is the next best thing?
Example:
// --- some C code I can not change ---
typedef void(*fun)(int);
void register_callback(fun f) {
f(42); // a test
}
// ------------------------------------
#include <functional>
#include <iostream>
void foo(const char* ptr, int v, float x) {
std::cout << ptr << " " << v << " " << x << std::endl;
}
int main() {
std::function<void(int)> myf = std::bind(&foo, "test", std::placeholders::_1, 3.f);
register_callback(myf); // <-- How to do this?
}
In most cases you can't.
But when you store a C style callback in your std::function, you can use the target() member function.
Long answer: sort of. You can write a C function to pass to the API that calls your std::function:
// --- some C code I can not change ---
typedef void(*fun)(int);
void register_callback(fun f) {
f(42); // a test
}
// ------------------------------------
#include <functional>
#include <iostream>
void foo(const char* ptr, int v, float x) {
std::cout << ptr << " " << v << " " << x << std::endl;
}
namespace {
std::function<void(int)> callback;
extern "C" void wrapper(int i) {
callback(i);
}
}
int main() {
callback = std::bind(&foo, "test", std::placeholders::_1, 3.f);
register_callback(wrapper); // <-- How to do this?
}
Related
In C++, I want to use a map of functions with different type of input or output.
Do to so, I found that using a map with any type could be a way.
But I get several problems. First, I can not use directly the functions in the map.
However, I can use a lambda function to wrap the functions then use these lambda functions in the map.
But, I get a second problem, I still need to cast with the lambda function which is not a variable. This makes a use from a string variable complicated.
Here is a MWE:
#include <any>
#include <functional>
#include <iostream>
#include <map>
#include <string>
void funct0()
{
std::cout << "funct0" << std::endl;
}
void funct1(int p)
{
std::cout << "funct1 " << p << std::endl;
};
int funct2(int p, std::string s)
{
std::cout << "funct2 " << s << std::endl;
return p+1;
};
float funct3(int a, float b)
{
std::cout << "funct3 " << std::endl;
return a +b;
}
auto funct4(int a, float b)
{
std::cout << "funct4 " << std::endl;
std::vector<float> v;
v.push_back(a);
v.push_back(b);
return v;
}
int main()
{
std::map<std::string, std::any> mapFunct;
mapFunct["F0"]= funct0;
// mapFunct["FO"](); // error: no match for call to ‘(std::map<std::__cxx11::basic_string<char>, std::any>::mapped_type {aka std::any}) ()’
mapFunct["F1"]= funct1;
// mapFunct["F1"](12); // error: no match for call to ‘(std::map<std::__cxx11::basic_string<char>, std::any>::mapped_type {aka std::any}) (int)’
// WHY THIS IS NOT WORKING ?
// From this link: https://stackoverflow.com/questions/61969316/is-it-possible-to-put-lambda-expressions-into-a-map-or-list-in-c
auto lambda0 = [](){funct0();};
auto lambda1 = [](int p) { funct1(p); return p; };
auto lambda2 = [](int p, std::string s) { return funct2(p,s); };
auto lambda3 = [](int a, float b){return funct3(a,b);};
auto lambda4 = [](int a, float b){return funct4(a,b);};
std::map<std::string, std::any> mapLambda;
mapLambda["L0"]=lambda0;
mapLambda["L1"]=lambda1;
mapLambda["L2"]=lambda2;
mapLambda["L3"]=lambda3;
mapLambda["L4"]=lambda4;
std::any_cast<decltype(lambda0)>(mapLambda["L0"])();
std::any_cast<decltype(lambda1)>(mapLambda["L1"])(2);
std::cout << std::any_cast<decltype(lambda2)>(mapLambda["L2"])(4, "HELLO") << std::endl;
std::cout << std::any_cast<decltype(lambda3)>(mapLambda["L3"])(3, 4.32) << std::endl ;
auto vec4= std::any_cast<decltype(lambda4)>(mapLambda["L4"])(6, 9.1);
std::cout << "vec4" << vec4[1] << vec4[2] << std::endl ;
std::vector<std::string> inputString;
inputString.push_back("L3(3, 4.32)");
inputString.push_back("L4(6, 9.1)");
// Using a for loop with iterator
for(auto it = std::begin(inputString); it != std::end(inputString); ++it) {
std::cout << *it << "\n";
std::string line=*it;
std::string functionInput = line.substr( 0, line.find("(") );
std::cout << functionInput << std::endl;
// argumentsInput= ;
mapLambda[functionInput](argumentsInput);
}
};
So my question are:
Why my example is working with lambda functions and not the functions ?
How can I make the last part of my example works only from the inputString variable? (ie, knowing the correct casting from the string variable)
What you probably want is something like this:
using CallWrapper = std::function<void(const std::string&)>;
std::map<std::string, CallWrapper> mapLambda;
mapLambda["L0"] = [funct0](const std::string&) { funct0(); };
mapLambda["L1"] = [funct1](const std::string& args) {
int p = ...; // parse the argument from `args`
funct1(p);
};
mapLambda["L2"] = [funct2](const std::string& args) {
// parse the arguments from `args`
int p = ...;
std::string s = ...;
funct2(p, s);
};
Now you can run the loop you envision:
for(const std::string& line : inputString) {
size_t pos = line.find('(');
std::string functionInput = line.substr( 0, pos);
std::string argumentsInput = line.substr(pos);
mapLambda[functionInput](argumentsInput);
}
The hard part, of course, is "parse the arguments from args", left as an exercise for the reader.
std::any_cast needs to cast to constructible types. A standard C++ function is neither a type nor constructible (it's just a group of statements given a name [edit: this isn't technically true, but what's going on under the hood is fairly complicated]), but std::function is. One way to get around this is to assign a standard C++ function to an std::function. Here's an example using a std::map like you were using:
#include <any>
#include <functional>
#include <iostream>
#include <map>
int my_func(int val) { return val + 1; }
std::function<int(int)> f = my_func;
int main() {
auto my_map = std::map<std::string, std::any>();
my_map["func"] = f;
std::cout << std::any_cast<std::function<int(int)>>(my_map["func"])(13) << std::endl; // prints "14"
return 0;
}
Lambdas are constructible types, which is why your code works for lambdas.
To answer your second question: I don't think it's possible. Functions with different signatures are different types, and you have to know what you're casting to. std::function<int(int, string)> and std::function<float(int, float)>, for example, are different types.
Also, the intended purpose of lambdas is to be used once then discarded. If you're going to keep lambdas around for reuse, it's better to simply just use functions.
In one of my projects I'm using a small utility function, which takes a Message struct and a lambda function, that modifies this message struct.
Now, I unintentionally passed a lambda without the necessary reference &. It perfectly compiles, but doesn't gave the desired output.
As for me, there should be one of the two following behaviors:
Forgetting to write auto&, but just auto should lead to compilation errors
Writing just auto should be interpreted as auto&.
It is possible to prevent compilation in case of a missing & or even better to interpret auto as auto& automatically?
#include <iostream>
#include <functional>
#include <boost/variant.hpp>
struct Message {
int x;
int y;
};
void changeMessage(Message& m, const std::function<void(Message&)>& messageModifier) {
std::cout << "Message before:" << m.x << " " << m.y << "\n";
messageModifier(m);
std::cout << "Message after:" << m.x << " " << m.y << "\n";
}
int main(int, char**) {
{
std::function<void(int&)> f = [](int&) {};
std::function<void(int)> g = [](int) {};
f = g; // This compiles.
}
{
std::function<void(int&)> f = [](int&) {};
std::function<void(int)> g = [](int) {};
//g = f; // This does not compile. Makes perfect sense.
}
Message m{ 10,20 };
{
changeMessage(m, [](auto m) { m.x++; m.y--; }); // User unintentionally forgot &! Can I prevent this from compilation?
std::cout << "Message outside: " << m.x << " " << m.y << "\n";
}
{
changeMessage(m, [](auto& m) { m.x++; m.y--; });
std::cout << "Message outside: " << m.x << " " << m.y << "\n";
}
}
One way to prevent passing Message by value (and auto itself is never a reference) is to disable copy construction:
struct Message {
Message() = default;
Message(const Message&) = delete;
int x;
int y;
};
Another solution suggested by #L. F. is to check that lambda doesn't accept rvalues:
template<class Fn>
void change_message(Message& m, Fn fn) {
static_assert(!std::is_invocable_v<Fn, Message&&>);
fn(m);
}
I have 3 algorithms function:
void algo1(int para1, int para2);
void algo2(int para1, int para2);
void algo3(int para1, int para2);
and I want set a timer to test these functions' efficiency
int get_execute_time( void(*f)(int para1, int para2) );
I pass the function as parameter to get_execute_time to avoid abundance, however, the problem is I also need to pass the arguments, which is para1, para2.
so I let timer function change to
get_execute_time( void(*f)(int para1, int para2) ,
int para1, int para2) {
(*f)(para1, para2); // call it
}
and, the code above seems ugly to me, so is there any option to wrap the code and let the code execute later in C++?
so that I can do like this:
// definition
get_execute_time(this_code_will_execute_later) {
this_code_will_execute_later();
};
// usage
get_execute_time(algo1(para1, para2));
Temporary solution: utilize class to implement closure-like thing( inspired from Do we have closures in C++?
class timer {
private:
int para1;
int para2;
public:
timer(int para1, int para2);
operator () (void(*f)(int para1, int para2)) { (*f)(para1, para2) }
}
// thus we can write these following code
timer timer(para1, para2);
std::cout << "run " << timer(algo1) << " ms";
std::cout << "run " << timer(algo2) << " ms"
std::cout << "run " << timer(algo3) << " ms"
So, Do exist better options? Thanks anyway!
You can do this with either std::bind or via a lambda. For example (just one parameter shown for brevity):
#include <iostream>
#include <functional>
void get_execute_time (std::function <void (void)> f)
{
f ();
}
void foo (int i)
{
std::cout << i << '\n';
}
int main()
{
int param = 42;
auto f1 = std::bind (foo, param);
get_execute_time (f1);
++param;
auto f2 = [param] { foo (param); };
get_execute_time (f2);
}
Output:
42
43
Live demo
I want to implement a function like this
double d = string_to("1223.23",double);
int i = string_to("1223",int);
bool d = string_to("1",bool);
How can I pass the bool, int, double data type to implement this in c++?
Types line int, double and bool can only be passed as template parameters.
You can use templates like this:
#include <string>
#include <sstream>
#include <iostream>
template<typename DataType>
DataType string_to(const std::string& s)
{
DataType d;
std::istringstream(s) >> d; // convert string to DataType
return d;
}
int main()
{
double d = string_to<double>("1223.23");
int i = string_to<int>("1223");
bool b = string_to<bool>("1");
std::cout << "d: " << d << '\n';
std::cout << "i: " << i << '\n';
std::cout << "b: " << b << '\n';
}
As an alternative you can pass your numeric types by reference and rely on function overloading to select the correct function:
void string_to(const std::string& s, double& d)
{
d = std::stod(s);
}
void string_to(const std::string& s, int& i)
{
i = std::stoi(s);
}
void string_to(const std::string& s, bool& b)
{
std::istringstream(s) >> std::boolalpha >> b;
}
int main()
{
double d;
int i;
bool b;
string_to("1223.23", d);
string_to("1223", i);
string_to("true", b);
std::cout << "d: " << d << '\n';
std::cout << "i: " << i << '\n';
std::cout << "b: " << b << '\n';
}
Also you could templatize the second method (an exercise for the reader).
If you really want to do this, you can pass the type by using the typeid operator.
E.g. double d = string_to("1223.23", typeid(double));
Using the library functions atoi, stod would make more sense.
If you're aiming to write more uniform code then you could write a Converter object and use method overloading to get automatic selection by type.
class Converter
{
public:
void fromString(double& value, const char* string);
void fromString(int& value, const char* string);
void fromString(long& value, const char* string);
};
Here's another way that uses tag dispatching. You can compile and run this example.
#include <iostream>
#include <string>
#include <cmath>
namespace detail {
// declare the concept of conversion from a string to something
template<class To>
To string_to(const std::string&);
// make some models of the concept
template<>
int string_to<int>(const std::string& s) {
return atoi(s.c_str());
}
template<>
double string_to<double>(const std::string& s) {
return atof(s.c_str());
}
template<>
std::string string_to<std::string>(const std::string& s) {
return s;
}
// ... add more models here
}
// define the general case of conversion from string with a model tag
// note the unused parameter allows provision of a model that is never used
// thus the model will in all likelihood be optimised away
template<class To>
To string_to(const std::string& from, const To& /* model_tag is unused */)
{
// dispatch to correct conversion function using the To type
// as a dispatch tag type
return detail::string_to<To>(from);
}
using namespace std;
int main()
{
// examples
int a = string_to("100", a);
double b = string_to("99.9", b);
const string s = string_to("Hello", s);
cout << s << " " << a << " " << b << endl;
return 0;
}
output:
Hello 100 99.9
I have this code that works already:
// mem_fun example
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
#include <string>
#include <sstream>
#include <map>
using namespace std;
struct C
{
C(int i): y_(i) {};
int y_;
string op1(int x)
{
std::ostringstream oss;
oss << "operation 1: " << x+y_;
return oss.str();
}
string op2(string x)
{
std::ostringstream oss;
oss << "operation 2: " << x << "+" << y_;
return oss.str();
}
};
struct container: map<string, C>
{
// doesn't compile
// void safeOperation(string key, ??? bound_function_and_arg_object )
template< typename argType >
void safeOperation(string key, string (C::*mf)(argType a), argType a)
{
iterator it = find(key);
if (it != end())
{
C* pC = &(it->second);
cout << (pC->*mf)(a) << "\n";
}
else
{
cout << "key: " << key << " missing\n";
}
}
};
int main () {
container objects;
objects.insert(container::value_type("a1", C(1)));
objects.insert(container::value_type("b2", C(2)));
objects.insert(container::value_type("c3", C(3)));
objects.safeOperation("a1", &C::op1, 1);
objects.safeOperation("b2", &C::op1, 2);
objects.safeOperation("d4", &C::op1, 4);
objects.safeOperation("c3", &C::op2, string("3"));
return 0;
}
I'd like to change the template function on the map to use std::mem_fun and to bind the parameters together with the operation, rather than specify them as separate parameters to safeOperation.
In other words, I'd prefer to call safeOperation similar to this:
// wrong, but hopefully communicates what I'm trying to do:
objects.safeOperation(someKey, bind(&C::op1, 4));
The sample code is here: http://cpp.sh/74pgb
I'm probably missing something simple, but appreciate the help.
When you bind a member function, the first argument has to be an instance of the class whose member function it is. So what you want to do is generalize safeOperation to take any function that can be called on a C*:
template< typename F >
void safeOperation(string key, F func) {
iterator it = find(key);
if (it != end())
{
C* pC = &(it->second);
cout << func(pC) << "\n";
}
else
{
cout << "key: " << key << " missing\n";
}
}
And then generate your funcs by binding with the argument, but also leaving a placeholder:
using namespace std:;placeholders;
objects.safeOperation("a1", std::bind(&C::op1, _1, 1));
// ^^
// placeholder for pC
boost/std::bind create an object with an implementation-specific type. The only requirement is that the object is callable using operator().
To handle any functional objects you can change your function template in the following way:
template< typename F >
void safeOperation(string key, F f)
{
// ...
cout << f(pC) << "\n";
// ...
objects.safeOperation("someKey", bind(&C::op1, placeholders::_1, 4));
That should enable almost the syntax you require.