Here is a sample design code of what I want to achieve. Basically I wanna store handler functions for different handlerNames and these handler functions can be of variable arguments.
The handler functions should be called on events with the required arguments are passed with Script::Handle(...)
How can I achieve this? Maybe its possible with Variadic Templates?
class Script
{
public:
Script() { /* ... */ }
template<typename TFunction>
void AddHandler(const char *handlerName, TFunction &&function)
{
_handlerMap[handlerName] = std::move(function);
}
void Handle(const char *handlerName, ...)
{
_handlerMap[handlerName](...);
}
private:
typedef std::map<std::string, std::function<void()>> HandlerMapType;
HandlerMapType _handlerMap;
};
//Handler functions
handlerOne() { std::cerr << "One"; }
handlerTwo(std::string a1, int a2) { std::cerr << "Two"; }
handlerThree(bool a1) { std::cerr << "Three"; }
int main(int argc, char **argv)
{
Script script;
script.AddHandler("One", std::bind(&handlerOne));
script.AddHandler("Two", std::bind(&handlerTwo));
script.AddHandler("Three", std::bind(&handlerThree));
script.Handle("One");
script.Handle("Two, "string", 96);
script.Handle("Three", true);
script.Handle("Three", "what should happen here?"); //String passed instead of bool
}
Let me prefix by saying that this is not a trivial thing to do in C++. And I will go as far to say that you should consider whether this is really something you need in your use case. In your example, you are asking for genericism that you can't really use. You will in any case need to know the signature of the function you are calling to call it properly; in that case what purpose is served by putting them in a container?
Generally, you'd do something like this if you are writing a middle layer of code. In your example, this would be equivalent to writing code that enables another user to call Handle. A common concrete example of this is to write a factory where objects in the factory may be instantiated using different arguments. However, it can't really be "different" arguments, at least not without some crazy casting. The solution is to make all the functions take the same argument, but make the argument a dynamic type that can store whatever arguments you want:
using argument_type = std::unordered_map<std::string, boost::any>;
void print(const argument_type & arg) {
auto to_print = boost::any_cast<std::string>(arg["to_print"]);
std::cerr << to_print << std::endl;
}
void print_none(const argument_type & arg) {
std::cerr << "none" << std::endl;
}
using my_func_t = std::function<void(const argument_type &)>;
std::vector<my_func_t> v;
v.emplace_back(print);
v.emplace_back(print_none);
// create some argument_types, feed them to f.
The above is not code that has been tested, nor with a working main, but I think this should give you a sense of how you could accomplish what you want.
edit: I thought about it a bit more, and I decided to elaborate a bit more on the "crazy casting" way. I suppose it's not really more crazy, but I strongly prefer what I showed above. The alternative is to completely type erase the functions themselves, and pass the arguments using a variadic template.
void print(std::string to_print) {
std::cerr << to_print << std::endl;
}
void print_none() {
std::cerr << "none" << std::endl;
}
std::vector<boost::any> v;
v.emplace_back(std::function<void(std::string)>(print));
v.emplace_back(std::function<void(void)>(print_none));
template <typename ... Args>
void call(const std::vector & funcs, int index, Args... args) {
auto f = boost::any_cast<std::function<void(Args...)>>(funcs[index]);
f(std::forward<Args>(args)...);
}
// unsure if this will actually work
call(f, 0, std::string("hello"));
The code above is very fragile though, because the types you pass to call will be deduced against, and then the cast will try to cast to a std::function that matches that signature. That exact signature. I don't have a lot of confidence that this will work out; if it's a reference, vs value, vs rvalue, etc. Casting back to a different std::function than what you put in is undefined behavior.
In summary, I'd either try to avoid needing to do this entirely, or go with the first solution. It's much less fragile, and it's better to be upfront about the fact that you are erasing the signatures of these functions.
Related
I want to get the active value in a std::variant without knowing which one is active. I thought i could write a template visitor and use std::visit but it doesn't work.
#include <variant>
#include <string>
#include <iostream>
struct Visit_configuration {
template<typename Data_type>
Data_type operator()(Data_type& t) const
{
return t;
}
};
int main()
{
std::variant<int, std::string> v;
v = "hello";
std::cout << std::visit(Visit_configuration(), v); // expect "hello"
std::cin.get();
}
MSVC doesn't compile and throws:
error C2338: visit() requires the result of all potential invocations
to have the same type and value category (N4741 23.7.7
[variant.visit]/2).
note: see reference to function template instantiation 'int
std::visit&,0>(_Callable
&&,std::variant &)' being compiled
So how to fix this?
edit: I want to use the obtained value maybe also for other so putting cout in the template isn't what im looking for.
Ask yourself the question:
What is the return type of std::visit if you don't know what part of the variant is active?
That is the question that the compiler must answer. And the answer can't be "it depends" - you (as in, the compiler) must decide on exactly one type at compile-time. The visit call cannot possibly return different types at runtime.
If you want to work with different types "at runtime", you must be in a function templated on the type you want to work with. In other words, there must be different functions (or function template instantiations) to handle the "write an int to cout" and "write a string to cout" cases. You cannot do this in the same (non-templated) function.
The straightforward solution here is thus to put the std::cout << into your templated visitor function - that's the point of visiting: Specifying what is supposed to happen in each case.
If you want to "use the obtained value maybe also for [some] other [purpose]", then that "other purpose" should also be part of the/a visitor. Only then can you have that "other purpose" handle the different cases at once (e.g. in a templated function). Otherwise you must decide at compile-time already which type shall be used - the compiler is not going to leave that choice open for later (run time).
Return type of visitor function should be identical.
Create printer visitor instead:
struct PrinterVisitor {
template<typename T>
void operator()(const T& t) const
{
std::cout << t;
}
};
int main()
{
std::variant<int, std::string> v;
v = "hello";
std::visit(PrinterVisitor{}, v); // expect "hello"
}
And in your case, you can even have lambda:
int main()
{
std::variant<int, std::string> v;
v = "hello";
std::visit([](const auto& t){std::cout << t;}, v); // expect "hello"
}
I must be misunderstanding something because I thought the two cases are the same:
#include <iostream>
void function() { std::cout << "Hi\n"; }
int main()
{
std::vector<void(*)()> funcPtrVec;
std::vector<void()> funcVec;
funcPtrVec.push_back(function); // Works
funcVec.push_back(function); // Works
auto lambdaFunc = []() { std::cout << "Hi\n"; };
funcPtrVec.push_back(lambdaFunc); // Works
funcVec.push_back(lambdaFunc); // Doesn't work
}
Now, in both cases my compiler says that the function signatures are the same, void function() and void lambdaFunc(). I really thought that when a lambda function doesn't capture anything it behaves like a free function, which the same signatures would seem to support. Also, I guess I'm confused even more due to the fact that in the following all seem to be treated the same, as if decaying to the same thing:
void function() { std::cout << "Hi\n"; }
void funcTakingFunc(void()) {}
void funcTakingFuncPtr(void(*)()) {}
int main()
{
auto lambdaFunc = []() { std::cout << "Hi\n"; };
void(*funcPtr)() = lambdaFunc; // Works
funcTakingFuncPtr(lambdaFunc); // Works
funcTakingFuncPtr(funcPtr); // Works
funcTakingFunc(lambdaFunc); // Works
funcTakingFunc(funcPtr); // Works
// They all work
}
So as far as I can see the only distinction between the function and the function pointer made is when given as a template argument to vector. This obviously means I don't understand templates well, but what's the reason for this? Because the two really seem the same from the examples I tried.
std::vector<void()> is not allowed; the type must be an object type, and a function type is not an object type.
There are various parts of the specification of vector requirements we could identify as being violated by a non-object type; the most obvious is the default allocator. In the table in [allocator.requirements]/2 it is specified that the type the allocator is for must be an object type.
I'm writing a little event manager class where I store some function pointers inside a vector. I use std::function<void(int)> as vector type, I tested inserting inside it lambdas and normal functions and it works:
void t(int p){
/*things*/
}
[...]
event.bind([](int p){/*things*/});
event.bind(t);
Now, (at a certain point I need to delete lambdas but not functions,) my question is:
Is it possible to distinguish lambdas from functions? If yes, how?
EDIT:
Since I clarified my doubts, this question becomes just what the title says
The real answer is: you don't want to do this. It defeats the point of type-erasing functors if you actually want to know the original type also in case of whatever. This just smells like bad design.
What you are potentially looking for is std::function::target_type. This is a way to pull out the underlying type_info of the target function that the function object is storing. Each type_info has a name(), which can be demangled. Note that this is a very deep rabbit hole and you're basically going to have to hard-code all sorts of weird edge-cases. As I've been doing thanks to Yakk's very loving help.
Different compilers mangle their lambda names differently, so this approach doesn't even resemble portability. Quick checking shows that clang throws in a $ while gcc throws {lambda...#d}, So we can attempt to take advantage of that by writing something like:
bool is_identifier(std::string const& id) {
return id == "(anonymous namespace)" ||
(std::all_of(id.begin(), id.end(),
[](char c){
return isdigit(c) || isalpha(c) || c == '_';
}) && !isdigit(id[0]));
}
bool is_lambda(const std::type_info& info)
{
std::unique_ptr<char, decltype(&std::free)> own {
abi::__cxa_demangle(info.name(), nullptr, nullptr, nullptr),
std::free
};
std::string name = own ? own.get() : info.name();
// drop leading namespaces... if they are valid namespace names
std::size_t idx;
while ((idx = name.find("::")) != std::string::npos) {
if (!is_identifier(name.substr(0, idx))) {
return false;
}
else {
name = name.substr(idx+2);
}
}
#if defined(__clang__)
return name[0] == '$';
#elif defined(__GNUC__)
return name.find("{lambda") == 0;
#else
// I dunno?
return false;
#endif
}
And then throw that in your standard erase-remove idiom:
void foo(int ) { }
void bar(int ) { }
long quux(long x) { return x; }
int main()
{
std::vector<std::function<void(int)>> v;
v.push_back(foo);
v.push_back(bar);
v.push_back(quux);
v.push_back([](int i) { std::cout << i << '\n';});
std::cout << v.size() << std::endl; // prints 4
v.erase(
std::remove_if(
v.begin(),
v.end(),
[](std::function<void(int)> const& f){
return is_lambda(f.target_type());
}),
v.end()
);
std::cout << v.size() << std::endl; // prints 3
}
No, not in general.
A std::function<void(int)> can store a function pointer to any function that can be called by passing a single rvalue int. There are an infinite number of such signatures.
The type of a lambda is an unique anonymous class for each declaration. Two distinct lambdas do not share any type relationship.
You can determine of a std::function<void(int)> stores a variable of a specific type, but in both the function pointer and lambda case there is an unbounded number of different types that can be stored in the std::function to consider. And you can only test for "exactly equal to a type".
You can access the type id information, but there is no portable representation there, and generally using that information for anything other than identity matching (and related) or debugging is a bad idea.
Now, a restricted version of the question (can you tell if a std::function<void(int)> contains a function pointer of type void(*)(int)) is easy to solve. But in general, doing so remains a bad idea: first, because it is delicate (code far away from the point you use it, like a subtle change to the function signature, can break things), and second, inspecting and changing your behavior based on the type stored in a std::function should only be done in extreme corner cases (usually involving updating your code from using void* style callbacks to std::function style callbacks).
Be it a function pointer or lambda, it ends up as a std::function<void(int)> in the vector. It is then std::function<void(int)>'s responsibility to manage the function pointer or lambda, not yours. That means, you just remove the std::function<void(int)>s you want from the vector. The destructor of std::function<void(int)> knows how to do things right. In your case, that would be doing nothing with function pointers and invoking the destructor of lambdas. std::function<void(int)> enables you to treat different things in a nice and uniform way. Don't misuse it.
NOTE: This answer presupposes that there is a finite, distinct number of function signatures that may be assigned as event handlers. It assumes that assigning any-old function with the wrong signature is a mistake.
You can use std::function::target to determine which ones are the function pointers and by process of elimination figure out which ones must be the lambdas:
void func1(int) {}
void func2(double) {}
int main()
{
std::vector<std::function<void(int)>> events;
events.push_back(func1);
events.push_back([](int){});
events.push_back(func2);
for(auto& e: events)
{
if(e.target<void(*)(int)>())
std::cout << "funcion int" << '\n';
else if(e.target<void(*)(double)>())
std::cout << "funcion double" << '\n';
else
std::cout << "must be lambda" << '\n';
}
}
This works because std::function::target returns a null pointer if the parameter type doesn't match.
Single variable example:
void func(int) {}
int main()
{
std::function<void(int)> f = func;
if(f.target<void(*)(int)>())
std::cout << "not a lambda" << '\n';
}
I have a series of member functions that are all very similar, and I think I might be able to make my code more maintainable with a template or some other approach, but I am not sure how to do it.
Here is an example of one of my functions:
void CalController::bgc_cmd(const std::string& s) {
try {
this->cohort_ptr->md->set_bgcmodule(temutil::onoffstr2bool(s));
LOG(note) << "CalController turned bgc module to "
<< s <<" via cohort pointer...";
} catch (const std::runtime_error& e) {
LOG(warn) << e.what();
}
}
My other functions are identical except for:
function name (i.e. bgc_cmd(..), env_cmd(..), dsl_cmd(..)
member function (of the md class) that is called within the try...catch block
Essentially I'd like to avoid having to duplicate the try..catch block and LOG(..) message in each of my CalController::XXX_cmd(...) functions.
Using boost::function and or boost::bind would be fine, I am just going in circles and can't figure out how to set this up.
You could just write a member function to do all that stuff. No bind or template necessary since everything is a function on md that takes the same argument type. I'm going to use MD as the type of md, and I'm assuming onoffstr2bool returns a bool:
void set_cmd(void (MD::*fn)(bool), const std::string& name, const std::string& s)
{
try {
(this->cohort_ptr->md->*fn)(temutil::onoffstr2bool(s));
LOG(note) << "CalController turned " << name << " to "
<< s <<" via cohort pointer...";
} catch (const std::runtime_error& e) {
LOG(warn) << e.what();
}
}
Which you would then call like:
void CalController::bgc_cmd(const std::string& s) {
set_cmd(&MD::set_bgcmodule, "bgc module", s);
}
I think you can get what you want with a simple, regular function. No need for a template:
void CalController::do_cmd(boost::function<void (String)> fun, const std::string& s) {
try {
fun(temutil::onoffstr2bool(s));
LOG(note) << "CalController turned bgc module to "
<< s <<" via cohort pointer...";
} catch (const std::runtime_error& e) {
LOG(warn) << e.what();
}
}
Then you can make your other methods something like:
void CalController::bgc_cmd(const std::string& s) {
// here TypeOfMd is whatever the type is for this->cohort_ptr->md.
// This binds the "this pointer" for set_bgcmodule to this->cohort_ptr->md
do_cmd(boost::bind(&TypeOfMd::set_bgcmodule, this->chort_prt->md), s);
}
A few things to note here:
With C++11 lambdas and the new function classes boost isn't necessary
I think the above works, but I'm not sure that saving a few lines of code is worth the extra complexity and loss of readability. It may also get hard to maintain as you want to make minor changes like slightly different log messages for each method.
It's been a while since I wrote any C++ and even longer since I did any boost stuff so while I think the above is the right general idea, I'd be surprised if it actually compiled.
If using C++11, You can create a function with a more generic name, let's say exex_cmd.
You can then pass a lambda function as argument and execute it inside the try/catch block - no need for a template use.
//WARNING: Untested code - the point is that you get the idea. Modify at will.
void CalController::exec_cmd(const std::function<void (void)> func) {
try {
//Invoke lambda.
//The string is passed via closure implementation,
//but you can always pass it as normal argument if you want.
func();
LOG(note) << "CalController turned bgc module to "
<< s <<" via cohort pointer...";
} catch (const std::runtime_error& e) {
LOG(warn) << e.what();
}
}
Then, create 3 wrapper methods, invoking exec_cmd, but passing a different lambda as argument:
void CalcController::bgc_cmd(const std::string& s){
CalcController::exec_cmd([=] () {
//Taking closures into control, to avoid passing the string as argument.
this->cohort_ptr->md->set_bgcmodule(temutil::onoffstr2bool(s));
})
}
void CalcController::env_cmd(const std::string& s){
CalcController::exec_cmd([=] () {
//different function invocation here.
})
}
Similarly, you can do it for all your functions.
You can look here for more about C++11's lambdas.
A similar approach in plain-old C++ is to define a function pointer type and pass a function pointer to your exec_cmd, create normal functions following the type signature and pass them as arguments, or pass a member function pointer - You can look at Barry's answer for that.
I've read posts/articles about lambdas, function pointers, anonymous functions in general and other related things but nothing I've seen (I think) has hit on exactly what I'm looking to do.
It seems like accomplishing this should be pretty simple, but say I have a function containing things I always want to do when called, but each time I call it I want it to run a function I describe (and only need to use once) in the argument (this anonymous function being the only argument).
Assuming this function which accepts my anonymous function as its argument is in main.cpp so it's called from main is it possible to implement this in a simple way?
Basically I'm trying to figure out the syntax in C++ for going from this:
// Some function with partially duplicated code
void OriginalA()
{
DoThingsA();
// unique code
DoThingsB();
}
// Another function with partially duplicated code
void OriginalB()
{
DoThingsA();
// unique code
DoThingsB();
}
To this:
// Encapsulate shared functionality
// <param name="action">User defined action</param>
void UniqueWrapper(Action action)
{
DoThingsA();
action();
DoThingsB();
}
// New implmentation of A
void NewA()
{
UniqueWrapper(() =>
{
// unique code
});
}
// New implementation of B
void NewB()
{
UniqueWrapper(() =>
{
// unique code
});
}
Which I found as #1 here: http://www.wildbunny.co.uk/blog/2012/11/01/10-steps-to-becoming-a-better-programmer/
But a setup like this where literally all you would have to do for the call is:
theFunctionName(() => { /*unique things to do*/ });
If this ^^ is legal calling syntax then I'm just not sure how the parameter looks in the definition of theFunctionName, clearly it isn't (Action action) like in the example above.
Replace the Action argument with:
template<typename Function>
void UniqueWrapper(Function action) {
DoThingsA();
action(); // call the passed in function
DoThingsB();
};
Call it like this:
void NewA() {
UniqueWrapper([]() {});
// ^^^^^^^
// C++11 lambda syntax
}
Instead of a lambda you can also use function pointers, member functions (using std::mem_fn), or functors. Every kind of callable object will work.
There are multiple ways to do this, but not all will work on all platforms (e.g. because they'd require C++11 features (lambdas).
The more classic approach would be something like this (without an anonymous function):
#include <iostream>
typedef void(*Action)();
void UniqueWrapper(Action action) {
std::cout << "Generic Code 1" << std::endl;
action();
std::cout << "Generic Code 2" << std::endl;
}
void CustomAction(void) {
std::cout << "Custom Code" << std::endl;
}
int main(int argc, char **argv) {
UniqueWrapper(&CustomAction);
return 0;
}
Of course you could use some macro shenanigans to make this more "dynamic".
Once you accept C++11 code as well (which is required to have lambdas as explained), you can do something like this:
#include <iostream>
typedef void(*Action)();
void UniqueWrapper(Action action) {
std::cout << "Generic Code 1" << std::endl;
action();
std::cout << "Generic Code 2" << std::endl;
}
int main(int argc, char **argv) {
UniqueWrapper([](){
std::cout << "Custom Code" << std::endl;
});
return 0;
}
Of course, there's room for more changes, for example you could use std::function rather than a function pointer.