Call std::visit with passed lambdas - c++

I have a struct that contains a variant.
I want to write a member function for that struct that should run code depending on which type variant currently holds.
However, I have issues making it compile.
I don't want to use more "template shenanigans" like using a separate struct to define operator(T&) since it pollutes the syntax even more.
Here is an example:
struct Data {
std::variant<int, double> var;
//Into this function,multiple lambdas should be passed for cases that the user wants to handle
template<typename ... Funcs>
void apply(Funcs&&... funcs) {
std::visit(std::forward<Funcs>(funcs)...,var);
}
};
int main() {
Data d;
d.var = 4;
//variant holds int and lambda provided that takes int&, execute it:
d.apply([](int& i){
std::cout << "I am Int Poggers" << std::endl;
});
d.var = 0.0;
//variant holds double but no lambda passed that takes a double, hence nothing happens:
d.apply([](int& i){
std::cout << "I am Int Poggers" << std::endl;
});
}
and I even don't know what the compiler wants from me:
https://godbolt.org/z/oM4584anf

Your problem is that std::visit() needs a "visitor" that must handle every type of the std::variant.
However, I have issues making it compile. I don't want to use more "template shenanigans" like using a separate struct to define operator(T&) since it pollutes the syntax even more.
There is nothing complicated.
You can simply add a trivial struct (with deduction guide) as follows (and as proposed in the cppreference std::visit() page)
template<class... Ts> struct overloaded : Ts...
{ using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
Then, given that you want that your std::visit() return void, you can add, in your apply() method, a generic-do-nothing lambda
template<typename ... Funcs>
void apply(Funcs&&... funcs) {
std::visit(overloaded{ // <-- pass through overloaded
[](auto const &){}, // <-- and add this generic lambda
std::forward<Funcs>(funcs)...},var);
}
Now the first apply() call
d.apply([](int& i){
std::cout << "I am Int Poggers" << std::endl;
});
should compile calling the supplied lambda because is a better match (given that d contains an int) and the second call compile calling the do-nothing generic lambda, because the generic lambda is a better match for a double.

Related

Is there a way to avoid storage overhead when using a function as a callback?

Given the following setup:
// ***** Library Code *****
#include <concepts>
template <std::invocable CbT>
struct delegated {
explicit constexpr delegated(CbT cb) : cb_(std::move(cb)) {}
private:
[[no_unique_address]] CbT cb_;
};
// ***** User Code *****
#include <iostream>
namespace {
inline constexpr void func() {}
}
struct MyFunc {
constexpr void operator()() const {}
};
int main() {
void (*func_ptr)() = func;
auto from_func = delegated{func};
auto from_func_ptr = delegated{func_ptr};
auto from_lambda = delegated{[](){}};
auto from_functor = delegated{MyFunc{}};
std::cout << "func: " << sizeof(from_func) << "\n";
std::cout << "func_ptr: " << sizeof(from_func_ptr) << "\n";
std::cout << "lambda: " << sizeof(from_lambda) << "\n";
std::cout << "functor: " << sizeof(from_functor) << "\n";
}
It produces, on GCC-x86-64 (See on godbolt):
func: 8 <----- Unfortunate
func_ptr: 8 <----- Fair enough
lambda: 1 <----- Neat
functor: 1 <----- Neat
None of this is particularly surprising.
However, it's frustrating that an undecayed lambda is preferable to using a function. And adding a note that delegated{[]{func();}} reduces the storage overhead is not exactly user-friendly, and makes for a very poor library interface.
Is there a way to do away with the storage overhead in the func case while maintaining a consistent user-facing API?
My current suspicion is that this is not possible without resorting to macros, on account of func not having, or decaying into, any type that would distinguish it from other functions with the same signature. I'm hoping that I overlooked something.
N.B. I get that something along the lines of delegated<func>() is a possibility, but unless I can prevent delegated{func} while still allowing delegated{func_ptr}, then that would be practically pointless.
Edit: To clarify the context a little bit: I am writing delegated in a library, and I don't want users of said library to have to worry about this. Or at least have the process be compiler-assisted instead of being documentation-dependant.
There are no objects of function types. The type will be adjusted to be a function pointer, which is why you delegated{func} and delegated{func_ptr} are exactly the same thing and former cannot be smaller.
Wrap the function call inside a function object (lambda, if you so prefer) to avoid the overhead of the function pointer.
If you would like to prevent the accidental use of the adjusted/decayed function pointer case when user tries to pass a function, then you could use a deleted overload for function references. I don't know how that could be achieved with CTAD, but if you provide a function interface, it could be done like this:
constexpr auto
make_delegated(std::invocable auto CbT)
{
return delegated{std::move(CbT)};
}
template<class... Args>
constexpr auto
make_delegated(auto (&cb)(Args...)) = delete;
Edit: Combining ideas with Human-Compiler's answer
template <auto CbT>
constexpr auto
make_delegated_fun() {
return delegated{ []{ CbT(); } };
}
constexpr auto
make_delegated(std::invocable auto CbT)
{
return delegated{std::move(CbT)};
}
template<class... Args>
constexpr auto
make_delegated(auto (&cb)(Args...)) {
// condition has to depend on template argument;
// just false would cause the assert to trigger without overload being called.
static_assert(!std::is_reference_v<decltype(cb)>, "please use make_delegated_fun");
};
auto from_func1 = make_delegated(func); // fails to compile
auto from_func2 = make_delegated_fun<func>(); // OK
auto from_func_ptr = make_delegated(func_ptr); // OK, pointer overhead
auto from_lambda = make_delegated([](){}); // OK
auto from_functor = make_delegated(MyFunc{}); // OK
Caveat, this would prevent following, and the example wouldn't work using make_delegated_fun either so the message would be misleading. The example could easily be rewritten to use function pointers or capturing lambda though:
auto& fun_ref = condition ? fun1 : fun2;
make_delegated(fun_ref); // fails to compile, suggests make_delegated_fun
make_delegated_fun<fun_ref>(); // fails to compile, not constexpr
make_delegated(&fun_ref); // OK, pointer overhead
The only way to really remove the "storage" from a function like this is to use the value at compile-time. The only real way to accomplish this is through a non-type template argument.
A factory function could do this easily with little changes, and keeps the implementation simple. You just need to accept the callable object as a template non-type argument -- such as an auto parameter, so that its known at compile-time without any storage requirements.
One way to perform this is to just use your lambda-wrapping solution with the existing code:
template <auto Fn>
auto make_delegated() {
return delegated{ []{ Fn(); } };
}
Then the following works:
auto from_func = make_delegated<&func>();
std::cout << "func: " << sizeof(from_func) << "\n";
this yields the correct value:
func: 1
Live Example
As an alternative measure, you could also require the user to wrap the function itself in a sentinel type that carries the data:
template <auto Fn>
struct empty_func{
auto operator()() { return Fn(); }
};
This would be almost equivalent to using a lambda, though the user instead only has to do:
auto from_func = delegated{empty_func<&func>{}};
The point is just that the function needs to be carried at compile-time somewhere.
Passing the function pointer as a template argument does not require any space at runtime. For example:
template <auto F>
struct delegated_erased {
template <typename... argument_t>
auto operator()(argument_t&&... argument){
F(std::forward<argument_t>(argument)...);
}
};
auto from_func = delegated_erased<func>{};
std::cout << "func: " << sizeof(from_func) << "\n"; // 1
With a helper function, you can combine this with your code:
template <typename result, typename ... argument>
delegated<result> make_delegated(result(&)(argument...)) = delete;
template <typename T>
delegated<T> make_delegated(T f) {
return delegated{std::move(f)};
};
template <auto F>
delegated_erased<F> make_delegated(){
return {};
}
Which allows you to do:
auto from_func = make_delegated<func>();
//auto from_func = make_delegated(func); // error: call to deleted function 'make_delegated'
auto from_func_ptr = make_delegated(func_ptr);
auto from_lambda = make_delegated([](){});
auto from_functor = make_delegated(MyFunc{});

Is there a way to detect at compile time whether a generic lambda can be successfully invoked with a given set of parameter types?

I would like to be able to determine at compile time, given a generic lambda type, whether it can be invoked with a given set of parameter types. I have the following example C++14 implementation:
#include <iostream>
// helper function; this overload handles the case that the call is possible
// use SFINAE with the extra template parameter to remove this from consideration when the
// call is ill-formed
template <typename Func, typename... Args, typename = decltype(std::declval<Func>()(std::declval<Args>()...))>
auto eval(Func f, Args &&... args) { return f(args...); }
// special type returned from `eval()` when the call can't be done
struct invalid_call { };
// helper function; this overload handles the case that the call is not possible
template <typename Func>
invalid_call eval(Func f, ...) { return invalid_call{}; };
// bring in std::negation from C++17 to help create the below trait
template<class B>
struct negation : std::integral_constant<bool, !bool(B::value)> { };
// trait that determines whether `Func` can be invoked with an argument list of types `Args...`
template <typename Func, typename... Args>
using can_call = negation<std::is_same<decltype(eval(std::declval<Func>(), std::declval<Args>()...)), invalid_call>>;
// arbitary type that has no `operator+`
struct foo {};
int main()
{
auto func = [](auto a1, auto a2) -> decltype(a1 + a2) { return a1 + a2; };
using FuncType = decltype(func);
std::cout << "can call with (int, int): " << can_call<FuncType, int, int>::value << std::endl;
std::cout << "can call with (foo, foo): " << can_call<FuncType, foo, foo>::value << std::endl;
}
This example works fine as-is. What I don't like is the cumbersome way that the lambda must be declared:
auto func = [](auto a1, auto a2) -> decltype(a1 + a2) { return a1 + a2; };
That is, the trailing return type must be specified because C++14's deduced return types don't work with SFINAE. Return type deduction requires substitution of the argument list types into the callable's template call operator, and the program is ill-formed if an error occurs there.
Ideally, I would be able to do the following:
auto func = [](auto a1, auto a2) { return a1 + a2; };
and let the return type work itself out automatically; this would be the most intuitive interface to provide to my users. This is a very simple example, so the argument to the decltype() doesn't look bad, but in practice, the lambda might be several statements, which wouldn't work with this approach. So my question is:
Using any modern C++ techniques (C++14 would be best, but I'm open to newer features as well if needed), is there any way I can test at compile time whether a generic lambda can possibly be invoked with an arbitrary list of parameter types?
Sure, using the C++98 feature of macros
#define RETURNS(...) noexcept(noexcept(__VA_ARGS__))->decltype(__VA_ARGS__) { return __VA_ARGS__; }
then
auto func = [](auto a1, auto a2) RETURNS(a1+a2);
does it.
There is a C++20 proposal by our very own #Barry that makes this
auto func = [](auto a1, auto a2) => a1+a2;
without the use of macros.
In general, it is not possible, nor is it intended to be possible, to force the body of a function or lambda to be compiled to determine if a SFINAE expression is acceptable or not. Such errors are supposed to be hard, as this simplifies the work of C++ compilers; they don't have to be able to compile entire bodies of arbitrary functions and then cleanly backout to an errorless state while determining if overload resolution succeeds or not.
In the case of more than one return statement or a long set of complex types used in the return statement, you are out of luck. Write the decltype. Pray you get it right.

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.)

How does wrapping a function pointer and function object work in generic code?

The following template definition
template <typename Func, typename ReturnType, typename... Arguments>
class Command
{
public:
Command(Func f) : m_func(f) { }
ReturnType operator()(Arguments... funcArgs) { return m_func(funcArgs...); }
private:
Func m_func;
};
gives an error message with gcc 4.7.3 (error: field 'Command::m_func' invalidly declared function type) when instantiated with the following test code:
void testFunction(int i, double d)
{
std::cout << "TestFunctor::operator()(" << i << ", " << d << ") called." << std::endl;
}
int main()
{
void (&fRef)(int, double) = TestFunction;
Command<void(int, double), void, int, double> testCommand(fRef);
}
The error message also occurs if I pass TestFunction without the address-of operator into the testCommand constructor, but disappears if I pass either an explicitly named function pointer or use the address-of operator to pass the parameter. I'm under the impression that this code should work given Chapter 5 of Modern C++ Design.
What is the reasoning behind not being able to store a reference to a function, but function pointers work fine? Are there any workarounds that would allow this to compile without losing support for being able to pass functors as arguments to Command's constructor as well?
Changing one line could fix it:
Command<void(*)(int, double), void, int, double> testCommand(fRef);
The difference is, you're passing a function pointer now, instead of a function type. (Functions aren't copyable, but pointers are).
The reference fRef decays to a function pointer when you pass it.
I wouldn't suggest using std::function if performance mattered.
See it live on Coliru
Note that with a little rewriting, you can make it all work much nicer:
int main()
{
auto command = make_command(testFunction);
command(1, 3.14);
}
To do this, I'd suggest changing the Command template to be:
template <typename Func>
class Command
{
Func m_func;
public:
Command(Func f) : m_func(f) { }
template <typename... A> auto operator()(A... args) const
-> decltype(m_func(args...))
{ return m_func(args...); }
};
And now you can have type-deduction on the Func template parameter by having a factory function:
template <typename Func> Command<Func> make_command(Func f)
{
return Command<Func>(f);
}
See this approach live on Coliru too. Of course, the output it the same:
TestFunctor::operator()(1, 3.14) called.
C++11 offers an std::function template. You don't have to mess with function pointers.
You can pass those by reference, copy them, move them and they can even be used to store lambdas:
std::function<void()> func = []() { std::cout << "Hi" << std::endl; };

How to have template type deduced in std::function arguments with lambda?

I have a boost::variant and I would like to execute a functor only if the variant is of a special type, so I made up this function:
template<typename T, typename Variant>
void if_init(Variant& opt_variant, std::function<void(T)> functor){
if(auto* ptr = boost::get<T>(&opt_variant)){
functor(*ptr);
}
}
This works well, but I would like the type T to be deduced, so that I can write that:
if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
But the type is not deduced:
type_inference.cpp:19:5: error: no matching function for call to 'if_init'
if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
^~~~~~~
type_inference.cpp:10:6: note: candidate template ignored: failed template argument deduction
void if_init(Variant& opt_variant, std::function<void(T)> functor){
If I write:
if_init<double>(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
it works well.
Is there a way to have type T being deduced ? I would like to type T only once. Here the type is short, but in the real case, there are long types.
I'm using CLang 3.2.
Here is the full test case (the first call compiles not the second):
#include <iostream>
#include <functional>
#include <boost/variant.hpp>
typedef boost::variant<int, double> Test;
template<typename T, typename Variant>
void if_init(Variant& opt_variant, std::function<void(T)> functor){
if(auto* ptr = boost::get<T>(&opt_variant)){
functor(*ptr);
}
}
int main(){
Test b = 1.44;
if_init<double>(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
if_init(b, [](int var){ std::cout << "I'm int and set" << std::endl; });
return 0;
}
I recommend you think of std::function<Sig> as a container of any one functor that conforms to Sig as a signature -- and which can be replaced at any moment. This functionality comes in very handy for e.g. std::vector<std::function<Sig>> because such a container can then hold functors of different types.
In your case, because you only care to have just the one functor you really don't need the functionality of std::function<Sig>. As such, I recommend you declare your function template like so:
template<typename T, typename Variant, typename Functor>
void if_init(Variant& opt_variant, Functor functor);
If you are worried that this doesn't communicate that Functor must conform to a void(T) signature, please note that std::function<Sig> does not enforce that either: although obviously you will end up with a compilation error, it is not a nice one. It's planned to be changed (and maybe your implementation has that either), but changed to a different kind of error. Still not that helpful for your case.
I personally make use of template aliases (in the template parameter list) to both document and enforce what a functor should conform to. This ends up looking like:
// Documents that e.g. long l = std::forward<Functor>(functor)(42.)
// should be a valid expression -- a functor that returns int would
// also be accepted.
// Triggers a hard-error (typically a static_assert with a nice message)
// on violation.
template<typename Functor, Requires<is_callable<Functor, long(double)>>...>
R foo(Functor functor);
// Documents that this function template only participates in overload resolution
// if the functor conforms to the signature.
// Does not trigger a hard-error (necessary by design); if everything goes right
// then another overload should be picked up -- otherwise an error of the kind
// 'no matching overload found' is produced
template<typename Functor, EnableIf<is_callable<Functor, long(double)>>...>
R bar(Functor functor);
As to your exact question, the rules of C++ do not allow for a template parameter to be deduced in your case. It's really not an easily fixed 'problem', if it is one. You can find more information on this.