Should I avoid casting to std::function when passing lambdas as parameters? - c++

If I have a function which is required to produce a hook from an input object, should I try to do that without casting to std::function? With these 2 options, which should I pick and is option 2 a meaningful improvement?
std::function<void()> CreateHook(std::function<void()> f)
{
return []()
{
return Hook(f);
};
}
// option 1:
void Hook(std::function<void()> f)
{
// do something
}
// option 2:
<typename F>
void Hook(F f)
{
// do something
}

Type erase only when you need to. Either:
template<class F>
std::function<void()> CreateHook(F f) { return []() { return Hook(f); }; }
or even in C++1y:
template<class F>
auto CreateHook(F f) { return [f=std::move(f)]() { return Hook(f); }; }
but the second is probably overkill (the f=std::move(f) is not, but auto is, as I am guessing you will just store the return value in a std::function anyhow).
And if your Hook function is simple and stable:
template <typename F> void Hook(F f) {
// do something
}
but if it is large and complex:
void Hook(std::function<void()> f) {
// do something
}
because it lets you split interface from implementation.
The downside to this strategy is that some compilers suck at eliminating identical code in different functions causing binary size bloat, and it can cause some compile time bloat.
But if you defer type erasure in both cases, you can eliminate both two virtual function calls, and allow the compiler to inline the passed in f within the Hook body.
If however the interface for CreateHook cannot be changed, and Hook is only called from it, the template version of Hook is pointless, as it is only called with a std::function anyhow.

In your example the template is pointless, because it is only ever instantiated for T = std::function<void()> - the template overload is chosen by static type of f, not the runtime type.

Related

How do I manage declarations that require template parameters derived from recursive functors/lambdas?

I am attempting to build a clean and neat implementation of recursive-capable lambda self-scoping (which is basically a Y-combinator although I think technically not quite). It's a journey that's taken me to, among many others, this thread and this thread and this thread.
I've boiled down one of my issues as cleanly as I can: how do I pass around templated functors which take lambdas as their template parameters?
#include <string>
#include <iostream>
#define uint unsigned int
template <class F>
class Functor {
public:
F m_f;
template <class... Args>
decltype(auto) operator()(Args&&... args) {
return m_f(*this, std::forward<Args>(args)...);
}
};
template <class F> Functor(F)->Functor<F>;
class B {
private:
uint m_val;
public:
B(uint val) : m_val(val) {}
uint evaluate(Functor<decltype([](auto & self, uint val)->uint {})> func) const {
return func(m_val);
}
};
int main() {
B b = B(5u);
Functor f = Functor{[](auto& self, uint val) -> uint {
return ((2u * val) + 1u);
}};
std::cout << "f applied to b is " << b.evaluate(f) << "." << std::endl;
}
The code above does not work, with Visual Studio claiming that f (in the b.evaluate(f) call) does not match the parameter type.
My assumption is that auto & self is not clever enough to make this work. How do I get around this? How do I store and pass these things around when they are essentially undefinable? Is this why many of the Y-combinator implementations I've seen have the strange double-wrapped thing?
Any help or explanation would be enormously appreciated.
The only way I see is make evaluate() a template method; if you want to be sure to receive a Functor (but you can simply accept a callable: see Yakk's answer):
template <typename F>
uint evaluate(Functor<F> func) const {
return func(m_val);
}
Take in count that every lambda is a different type, as you can verify with the following trivial code
auto l1 = []{};
auto l2 = []{};
static_assert( not std::is_same_v<decltype(l1), decltype(l2)> );
so impose a particular lambda type to evaluate() can't work because if you call the method with (apparently) the same lambda function, the call doesn't match, as you can see in the following example
auto l1 = []{};
auto l2 = []{};
void foo (decltype(l1))
{ }
int main ()
{
foo(l2); // compilation error: no matching function for call to 'foo'
}
The easiest solution is:
uint evaluate(std::function<uint(uint)> func) const {
return func(m_val);
}
a step up would be to write a function_view.
uint evaluate(function_view<uint(uint)> func) const {
return func(m_val);
}
(there are dozens of implementations on the net, should be easy to find).
The easiest and most runtime efficient is:
template<class F>
uint evaluate(F&& func) const {
return func(m_val);
}
because we don't care what func is, we just want it to quack like a duck. If you want to check it early...
template<class F> requires (std::is_convertible_v< std::invoke_result_t< F&, uint >, uint >)
uint evaluate(F&& func) const {
return func(m_val);
}
using c++20, or using c++14
template<class F,
std::enable_if_t<(std::is_convertible_v< std::invoke_result_t< F&, uint >, uint >), bool> = true
>
uint evaluate(F&& func) const {
return func(m_val);
}
which is similar just more obscure.
You can write a fixes-signature type-erased Functor, but I think it is a bad idea. It looks like:
template<class R, class...Args>
using FixedSignatureFunctor = Functor< std::function<R( std::function<R(Args...)>, Args...) > >;
or slightly more efficient
template<class R, class...Args>
using FixedSignatureFunctor = Functor< function_view<R( std::function<R(Args...)>, Args...) > >;
but this is pretty insane; you'd want to forget what the F is, but not that you can replace the F!
To make this fully "useful", you'd have to add smart copy/move/assign operations to Functor, where it can be copied if the Fs inside each of them can be copied.
template <class F>
class Functor {
public:
// ...
Functor(Functor&&)=default;
Functor& operator=(Functor&&)=default;
Functor(Functor const&)=default;
Functor& operator=(Functor const&)=default;
template<class O> requires (std::is_constructible_v<F, O&&>)
Functor(Functor<O>&& o):m_f(std::move(o.m_f)){}
template<class O> requires (std::is_constructible_v<F, O const&>)
Functor(Functor<O> const& o):m_f(o.m_f){}
template<class O> requires (std::is_assignable_v<F, O&&>)
Functor& operator=(Functor<O>&& o){
m_f = std::move(o.mf);
return *this;
}
template<class O> requires (std::is_assignable_v<F, O const&>)
Functor& operator=(Functor<O> const& o){
m_f = o.mf;
return *this;
}
// ...
};
(c++20 version, replace requires clauses with std::enable_if_t SFINAE hack in c++17 and before).
How to decide
The core thing to remember here is that C++ has more than one kind of polymorphism, and using the wrong kind will make you waste a lot of time.
There is both compile time polymorphism and runtime polymorphism. Using runtime polymorphism when you only need compile time polymorphism is a waste.
Then in each category, there are even more subtypes.
std::function is a runtime polymorphic type erasure regular object. Inheritance based virtual functions is another runtime polymorphic technique.
Your Y-combinator is doing compile time polymorphism. It changes what it stores and exposed a more uniform interface.
Things talking to that interface don't care about the internal implementation details of your Y-combinator, and including them in their implementation is an abstraction failure.
evaluate takes a callable thing and pass it in uint and expects a uint in return. That is what it care about. It doesn't care if it is passed a Functor<Chicken> or a function pointer.
Making it care about it is a mistake.
If it takes a std::function, it does runtime polymorphism; if it takes a template<class F> with an argument of type F&&, it is compile time polymorphic. This is a choice, and they are different.
Taking a Functor<F> of any kind is putting contract requirements in its API it fundamentally shouldn't care about.

Template function signature unpacking in C++/CLI

Is there a way to apply the function-signature-as-template-parameter unpacking idiom in a way that works with C++/CLI managed types?
As an example, consider the following code:
#include <msclr/gcroot.h>
using namespace System;
template<typename... Args>
ref struct ManagedDelegate abstract
{
delegate void Fn(Args...);
};
template<typename Signature>
struct Method;
template<typename... Args>
struct Method<void(Args...)>
{
using Fn = typename ManagedDelegate<Args...>::Fn;
Method(Fn^ m) : m_Method(m) {}
void operator()(Args... args)
{
auto method = safe_cast<Fn^>(m_Method);
method(args...);
}
private:
msclr::gcroot<Fn^> m_Method;
};
void f1(int a, int b)
{
Console::WriteLine("a = {0}, b = {1}", a, b);
}
void f2(String^ s)
{
Console::WriteLine("s = {0}", s);
}
int main(array<String ^> ^args)
{
using Method1 = Method<void(int, int)>;
Method1 m1(gcnew Method1::Fn(&f1));
m1(4, 5);
using Method2 = Method<void(String^)>;
Method2 m2(gcnew Method2::Fn(&f2));
m2("hello world");
return 0;
}
(The separate ManagedDelegate is a little annoying, but it's not possible to declare a delegate type inside a native class, sadly.)
If you comment out all the Method2 code at the bottom, then this compiles and runs as you'd expect -- it calls f1(4, 5) and prints accordingly.
Trying to do the same thing with a managed type argument, however, causes the template to fail to match the specialisation and results in:
error C2027: use of undefined type 'Method<void (System::String ^)>'
Is this a compiler bug, or is there some way to get this to work? There are some constraints that I do need to keep to in order for this to work in my real code:
Method needs to be an unmanaged type that contains a gcroot of the delegate type.
The use of templates rather than generics is intended. I don't think any of this is possible with generics anyway.
The non-use of std::forward is also intended, since this also upsets managed types. (And I'm not intending to pass native reference arguments anyway, so it's unnecessary.)
While I prefer automatically creating the delegate type from the signature as shown here, it would also be acceptable to create the delegate outside and pass it in instead of a signature, eg:
delegate void Method1Delegate(int, int);
...
Method<Method1Delegate> m1(gcnew Method1Delegate(&f1));
But either way, I do need an Args... parameter list (both for the operator() and for other reasons). And I don't think it's possible to extract this from a managed delegate type.
I also want the operator() to keep using Args... from the Method type so that it won't accept the "wrong" parameters. (I did have an older version of the code that templated Args directly on operator(), but this gives IntelliSense the false impression that it would accept any parameters.)
If there is a way to do the above, then I'd probably want a version that works with a templated return type as well as just void. I know how to do that with the above code -- just that any rewrite shouldn't prevent that working if possible.
EDIT: as demonstration that the managed args sort of work in variadics, this can be added:
template<>
struct Method<void(String^)>
{
using Fn = typename ManagedDelegate<String^>::Fn;
Method(Fn^ m) : m_Method(m) {}
template<typename... Args>
void operator()(Args... args)
{
auto method = safe_cast<Fn^>(m_Method);
method(args...);
}
private:
msclr::gcroot<Fn^> m_Method;
};
This works, provided that the call is changed to m2(gcnew String("hello world")); to force the correct type, or operator() is changed to accept a single String^ parameter instead of an open variadic. So the problem is definitely in matching a variadic template specialisation, not elsewhere.
I can mostly do what I want by abandoning the function-signature-specialisation and just specifying the signature components separately:
template<typename R, typename... Args>
ref struct ManagedDelegate abstract
{
delegate R Fn(Args...);
};
template<typename R, typename... Args>
struct Method
{
using Fn = typename ManagedDelegate<R, Args...>::Fn;
Method(Fn^ m) : m_Method(m) {}
R operator()(Args... args)
{
auto method = safe_cast<Fn^>(m_Method);
return method(args...);
}
private:
msclr::gcroot<Fn^> m_Method;
};
//...
using Method2 = Method<void, String^>;
Method2 m2(gcnew Method2::Fn(&f2));
m2("hello world");
This is not ideal, but it does compile and work. I'm still interested in any alternative answer that does support unpacking a function signature type, however. (And I filed the original issue as a compiler bug.)

Execute integer templated function based on run-time parameter

I often have some prototype behaviour that generates output based on some design method. I template the design method, which enables a lot of functionality I need. However, sometimes the design method is given at runtime, so I'm usually required to write a huge switch statement. It usually looks like this:
enum class Operation
{
A, B
};
template<Operation O>
void execute();
template<>
void execute<A>()
{
// ...
}
template<>
void execute<B>()
{
// ...
}
void execute(Operation o)
{
switch (o)
{
case Operation::A: return execute<Operation::A>();
case Operation::B: return execute<Operation::B>();
}
}
I'm curious as to whether anyone has figured out a nice pattern for this system - the main drawbacks of this method is that one has to type out all the supported enumerations and do maintenance several places if new enumerations are implemented.
e: I should add that the reasons for messing with compile-time templates is to allow the compiler to inline methods in HPC as well as inherit constexpr properties.
e2: in effect, I guess what I'm asking is to have the compiler generate all the possible code paths using an implicit switch structure. Perhaps some recursive template magic?
If you really want to utilize templates for this task you can use technique similar to this one.
// Here second template argument default to the first enum value
template<Operation o, Operation currentOp = Operation::A>
// We use SFINAE here. If o is not equal to currentOp compiler will ignore this function.
auto execute() -> std::enable_if<o == currentOp, void>::type
{
execute<currentOp>();
}
// Again, SFINAE technique. Compiler will stop search if the template above has been instantiated and will ignore this one. But in other case this template will be used and it will try to call next handler.
template<Operation o, Operation currentOp = Operation::A>
void execute()
{
return execute<o, static_cast<Operation>(static_cast<int>(currentOp) + 1)(c);
}
template<class F, std::size_t...Is>
void magic_switch( std::size_t N, F&& f, std::index_sequence<Is...> ){
auto* pf = std::addressof(f);
using pF=decltype(pf);
using table_ptr = void(*)(pF);
static const table_ptr table[]={
[](pF){ std::forward<F>(*pf)( std::integral_constant<std::size_t, Is>{} ); }...
};
return table[N]( pf );
}
template<std::size_t Count, class F>
void magic_switch( std::size_t N, F&& f ){
return magic_switch( N, std::forward<F>(f), std::make_index_sequence<Count>{} );
}
This makes a jump table that invokes a lambda on a compile time constant, picking which entry based on a runtime constant. Which is very similar to how a switch case statement is compiled to sometimes.
void execute(Operation o) {
magic_switch<2>( std::size_t(o), [](auto I){
execute<Operation(I)>();
} );
}
Modifying it to return non-void is possible, but all branches must return the same type.

Containers for different signature functions

I'm trying to programming in C++ a framework where the user can indicates a set of functions inside its program where he wants to apply a memoization strategy.
So let's suppose that we have 5 functions in our program f1...f5 and we want to avoid the (expensive) re-computation for the functions f1 and f3 if we already called them with the same input. Notice that each function can have different return and argument types.
I found this solution for the problem, but you can use only double and int.
MY SOLUTION
Ok I wrote this solution for my problem, but I don't know if it's efficient, typesafe or can be written in any more elegant way.
template <typename ReturnType, typename... Args>
function<ReturnType(Args...)> memoize(function<ReturnType(Args...)> func)
{
return ([=](Args... args) mutable {
static map<tuple<Args...>, ReturnType> cache;
tuple<Args...> t(args...);
auto result = cache.insert(make_pair(t, ReturnType{}));
if (result.second) {
// insertion succeeded so the value wasn't cached already
result.first->second = func(args...);
}
return result.first->second;
});
}
struct MultiMemoizator
{
map<string, boost::any> multiCache;
template <typename ReturnType, typename... Args>
void addFunction(string name, function < ReturnType(Args...)> func) {
function < ReturnType(Args...)> cachedFunc = memoize(func);
boost::any anyCachedFunc = cachedFunc;
auto result = multiCache.insert(pair<string, boost::any>(name,anyCachedFunc));
if (!result.second)
cout << "ERROR: key " + name + " was already inserted" << endl;
}
template <typename ReturnType, typename... Args>
ReturnType callFunction(string name, Args... args) {
auto it = multiCache.find(name);
if (it == multiCache.end())
throw KeyNotFound(name);
boost::any anyCachedFunc = it->second;
function < ReturnType(Args...)> cachedFunc = boost::any_cast<function<ReturnType(Args...)>> (anyCachedFunc);
return cachedFunc(args...);
}
};
And this is a possible main:
int main()
{
function<int(int)> intFun = [](int i) {return ++i; };
function<string(string)> stringFun = [](string s) {
return "Hello "+s;
};
MultiMemoizator mem;
mem.addFunction("intFun",intFun);
mem.addFunction("stringFun", stringFun);
try
{
cout << mem.callFunction<int, int>("intFun", 1)<<endl;//print 2
cout << mem.callFunction<string, string>("stringFun", " World!") << endl;//print Hello World!
cout << mem.callFunction<string, string>("TrumpIsADickHead", " World!") << endl;//KeyNotFound thrown
}
catch (boost::bad_any_cast e)
{
cout << "Bad function calling: "<<e.what()<<endl;
return 1;
}
catch (KeyNotFound e)
{
cout << e.what()<<endl;
return 1;
}
}
How about something like this:
template <typename result_t, typename... args_t>
class Memoizer
{
public:
typedef result_t (*function_t)(args_t...);
Memoizer(function_t func) : m_func(func) {}
result_t operator() (args_t... args)
{
auto args_tuple = make_tuple(args...);
auto it = m_results.find(args_tuple);
if (it != m_results.end())
return it->second;
result_t result = m_func(args...);
m_results.insert(make_pair(args_tuple, result));
return result;
}
protected:
function_t m_func;
map<tuple<args_t...>, result_t> m_results;
};
Usage is like this:
// could create make_memoizer like make_tuple to eliminate the template arguments
Memoizer<double, double> memo(fabs);
cout << memo(-123.456);
cout << memo(-123.456); // not recomputed
It's pretty hard to guess at how you're planning to use the functions, with or without memoisation, but for the container-of-various-function<>s aspect you just need a common base class:
#include <iostream>
#include <vector>
#include <functional>
struct Any_Function
{
virtual ~Any_Function() {}
};
template <typename Ret, typename... Args>
struct Function : Any_Function, std::function<Ret(Args...)>
{
template <typename T>
Function(T& f)
: std::function<Ret(Args...)>(f)
{ }
};
int main()
{
std::vector<Any_Function*> fun_vect;
auto* p = new Function<int, double, double, int> { [](double i, double j, int z) {
return int(i + j + z);
} };
fun_vect.push_back(p);
}
The problem with this is how to make it type-safe. Look at this code:
MultiMemoizator mm;
std::string name = "identity";
mm.addFunction(name, identity);
auto result = mm.callFunction(name, 1);
Is the last line correct? Does callFunction have the right number of parameters with the right types? And what is the return type?
The compiler has no way to know that: it has no way of understanding that name is "identity" and even if it did, no way to associate that with the type of the function. And this is not specific to C++, any statically-typed language is going to have the same problem.
One solution (which is basically the one given in Tony D's answer) is to tell the compiler the function signature when you call the function. And if you say it wrong, a runtime error occurs. That could look something like this (you only need to explicitly specify the return type, since the number and type of parameters is inferred):
auto result = mm.callFunction<int>(name, 1);
But this is inelegant and error-prone.
Depending on your exact requirements, what might work better is to use "smart" keys, instead of strings: the key has the function signature embedded in its type, so you don't have to worry about specifying it correctly. That could look something like:
Key<int(int)> identityKey;
mm.addFunction(identityKey, identity);
auto result = mm.callFunction(identityKey, 1);
This way, the types are checked at compile time (both for addFunction and callFunction), which should give you exactly what you want.
I haven't actually implemented this in C++, but I don't see any reason why it should be hard or impossible. Especially since doing something very similar in C# is simple.
you can use vector of functions with signature like void someFunction(void *r, ...) where r is a pointer to result and ... is variadic argument list. Warning: unpacking argument list is really inconvenient and looks more like a hack.
At first glance, how about defining a type that has template arguments that differ for each function, i.e.:
template <class RetType, class ArgType>
class AbstractFunction {
//etc.
}
have the AbstractFunction take a function pointer to the functions f1-f5 with template specializations different for each function. You can then have a generic run_memoized() function, either as a member function of AbstractFunction or a templated function that takes an AbstractFunction as an argument and maintains a memo as it runs it.
The hardest part will be if the functions f1-f5 have more than one argument, in which case you'll need to do some funky things with arglists as template parameters but I think C++14 has some features that might make this possible. An alternative is to rewrite f1-f5 so that they all take a single struct as an argument rather than multiple arguments.
EDIT: Having seen your problem 1, the problem you're running into is that you want to have a data structure whose values are memoized functions, each of which could have different arguments.
I, personally, would solve this just by making the data structure use void* to represent the individual memoized functions, and then in the callFunction() method use an unsafe type cast from void* to the templated MemoizedFunction type you need (you may need to allocate MemoizedFunctions with the "new" operator so that you can convert them to and from void*s.)
If the lack of type safety here irks you, good for you, in that case it may be a reasonable option just to make hand-written helper methods for each of f1-f5 and have callFunction() dispatch one of those functions based on the input string. This will let you use compile-time type checking.
EDIT #2: If you are going to use this approach, you need to change the API for callFunction() slightly so that callFunction has template args matching the return and argument types of the function, for example:
int result = callFunction<int, arglist(double, float)>("double_and_float_to_int", 3.5, 4);
and if the user of this API ever types the argument type or return types incorrectly when using callFunction... pray for their soul because things will explode in very ugly ways.
EDIT #3: You can to some extent do the type checking you need at runtime using std::type_info and storing the typeid() of the argument type and return type in your MemoizedFunction so that you can check whether the template arguments in callFunction() are correct before calling - so you can prevent the explosion above. But this will add a bit of overhead every time you call the function (you could wrap this in a IF_DEBUG_MODE macro to only add this overhead during testing and not in production.)

Fulfill a (possibly-void) promise

I'm writing some multithreaded code and using promise/future to call a function on a different thread and return its result. For simplicitly, I'll remove the threading part entirely:
template <typename F>
auto blockingCall(F f) -> decltype(f())
{
std::promise<decltype(f())> promise;
// fulfill the promise
promise.set_value(f());
// block until we have a result
return promise.get_future().get();
}
This works great for any function that returns non-void. And the return statement getting the future also works for void. But I can't fulfill the promise if f is a void function, because:
promise.set_value(f()); // error: invalid use of void expression
Is there some clever way of setting the value in the void case in-line, or do I have to just write a helper function like call_set_value(promise, f) that has an overloads for std::promise<R> and std::promise<void>?
A promise is only one kind of asynchronous result provider. Instead of a promise you could use a packaged_task which wraps a callable object, similar to a std::function except that invoking it makes the result available via a future (and of course it handles the difference between void and non-void results):
template <typename F>
auto blockingCall(F f) -> decltype(f())
{
std::packaged_task<decltype(f())()> task(std::move(f));
task();
// block until we have a result
return task.get_future().get();
}
N.B. according to the current standard, this code would have a data race if task() and task.get_future() happen on separate threads (and so would your original using a promise), so you should call get_future() before handing the task to the other thread. In practice it should be safe on real implementations and there's a library issue (LWG 2412) to make it valid anyway.
Yes. Function overload is the cleanest solution:
set(promise, f);
then implement set as overloaded functions, as:
template<typename F, typename R>
void set(std::promise<R> & p, F && f) //handle non-void here
{
p.set_value(f());
}
template<typename F>
void set(std::promise<void> & p, F && f) //handle void here
{
f();
p.set_value();
}