Lazy evaluation of apply function implemented with variate template in C++ - c++

I'm trying to write my own apply function using variate template. Here is the code I have:
template<typename...>
struct types{
};
template<typename T, typename... Args>
struct Func{
template<typename F, typanem... Types>
T call(F f, std::tuple<Types...>& params, Args... args){
return _call(f, params, types<Types...>{}, args...);
}
template<typename F, typename Tuple, typename Head, typename... Tail, typename... Args>
T _call(F f, Tuple& t, types<Head, Tail...>, Args&&... args){
_call(f, t, types<Tail...>{}, std::forward<Args>(args)..., std::get<sizeof...(Arg)>(t).DrawSample()));
}
T _call(F f, Tuple& t, types<>, Args... vs){
return f(vs...)
}
};
I can compile and run the above code without any difficulty. Now I want to make the function call(...) being invoked lazily. In other words, I can first construct the function by passing in all parameters needed for the computation:
int getMax(float f1, float f2, float f3){
if(f1 >= f2 && f1 >= f3){
return 1;
}
if(f2 >= f1 && f2 >= f3){
return 2;
}
if(f3 >= f1 && f3 >= f2){
return 3;
}
}
Func<int> func;
//Gaussian(mu, sd) is an object which can generate random values based on Gaussian
//distribution described with mu(mean) and sd(standard deviation).
Gaussian *g1 = Gaussian(0.3, 0.2);
Gaussian *g2 = Gaussian(0.2, 0.3);
Gaussian *g3 = Gaussian(0.3, 0.3);
func.setCall(getMax, std::make_tuple(*g1, *g2, *g3);
cout<<func.DrawSample();
After constructing the function, I hope to get the result of the getMax() function lazily each time I make a query for func.DrawSample(). Under the hood, perhaps DrawSample() calls call(...). However, is there anyway for me to change the code above in order to create a setCall(...) whose purpose is to store everything needed for later function calls?
Please let me know if my question is still unclear. Thanks a lot for your help!

Try this:
template<class Func, class... Args>
int applyDrawSample(Func func, Args... args)
{
return func(args.DrawSample()...);
}
template<class Func, class... Args>
auto bind_helper(Func func, Args... args)
-> decltype(bind(applyDrawSample<Func, Args...>, func, args...))
{
return bind(applyDrawSample<Func, Args...>, func, args...);
}
Usage:
auto func = bind_helper(getMax, Gaussian(...), Gaussian(...), Gaussian(...));
func();
A trivial extra lambda can change the last call to look like func->DrawSample(), if you really want it, and is left as an exercise.
EDIT
If you need a type for func above, it can be std::function:
function<int()> func = bind_helper(...);
The function signature (in this case, a function with no arguments, returning an int) for std::function needs to be compatible with what you are assigning.

Use std::function<int()> and lambdas.
std::function<int()> func;
func = [=]()->int {
return getMax( Guassian(0.3,0.2), Guassian(0.2,0.3), Guassian(0.3,0.3) );
};
std::cout << func();
If you really, really need your interface, simply store a std::function<T()> within your class, and the setCall simply assigns to it.
But really, your object is some anonymous type that can be invoked to produce an int -- std::function solves the problem. You'll have to engage in type erasure anyhow, as the type of your class does not include the function signature, so you probably won't be any more efficient.

With the suggestion provided by DanielKO, I finally come up with a solution for my specific scenario.
Here is the final version of my compiled code.
template<class Func, class... Args>
int applyDrawSample(Func func, Args&&... args){
return func((*args).DrawSample()...);
}
template<class Func, class... Args>
auto bind_helper(Func func, Args&&... args) ->decltype(bind(applyDrawSample<Func, Args...>,
func, args...))
{
return bind(applyDrawSample<Func, Args...>, func, args...);
}
template<typename T>
struct UncertainFunc{
template<typename F, typename... Args>
void setFunc(F f, Args... args){
function = bind_helper(f, args...);
}
T DrawSample(){
return function();
}
std::function<T()> function;
};
UncertainFunc<int> ufunc;
ufunc.setFunc(getMax, &(Gaussian(0.3, 0.2), &Gaussian(0.2, 0.3), &Gaussian(0.2, 0.2));
ufunc.DrawSample();
Especially, it seems that I cannot put the bind_helper(...) function into my class definition for some reason (perhaps auto type?).

Related

How to pass a Callable object in c++17 to be used with std::invoke

Why the following does not compile when passing i to the constructor. The other similar constructs compile.
#include <iostream>
#include <functional>
int RetXPrintU(int x, uint u)
{
std::cout << "RetXprintU(): " << u << std::endl;
return x;
}
template <typename Fn, typename... Args>
void Call(Fn&& fun, Args&&... args)
{
std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
}
template <typename Fn, typename... Args>
class CallableObj
{
public:
explicit CallableObj(Fn&& fun, Args&&... args)
{
std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
}
};
int main() {
int i = 4;
std::invoke(RetXPrintU, i, 8u);
Call(RetXPrintU, i, 8u);
CallableObj co(RetXPrintU, i, 8u); // WHY I DO NOT COMPILE?
//CallableObj co(RetXPrintU, 0, 8u); // WHY I COMPILE?
return 0;
}
The issue here is you need to move the template from the class to the constructor. When you have
template <typename Fn, typename... Args>
class CallableObj
{
public:
explicit CallableObj(Fn&& fun, Args&&... args)
{
std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
}
};
Args&&... is not a variadic forwarding reference because it is deduced for the class itself and when you call CallableObj co(RetXPrintU, i, 8u); the class is instantiated and the constructor gets stamped out as
explicit CallableObj(int(int, unsigned int)&& fun, int&& arg1, unsigned int&& arg2)
What we want is
class CallableObj
{
public:
template <typename Fn, typename... Args>
explicit CallableObj(Fn&& fun, Args&&... args)
{
std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
}
};
so that now Args will be deduced when the constructor is called and Args&& is now a forwarding reference.
The reason CallableObj co(RetXPrintU, 0, 8u); worked in your example is because 0 is a prvalue and a prvalue can bind to an rvalue reference.
As the error message says, the compiler can't deduce the template parameters for CallableObj. You need add a deduction guide for that:
template <typename Fn, typename... Args>
CallableObj(Fn&& fun, Args&&... args) -> CallableObj<Fn, Args>...>;
The whole code reads:
template <typename Fn, typename... Args>
class CallableObj
{
public:
explicit CallableObj(Fn fun, Args... args)
{
std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
}
};
template <typename Fn, typename... Args>
CallableObj(Fn&& fun, Args&&... args) -> CallableObj<Fn, Args...>;
As #Jarod42 pointed out there's no need to make the constructor a template itself (as it was in the first version of the answer).
And here is a live example (corrected version by #Jarod42).
I was assuming your code is just a minimal example and you need the class to be a template. If that is not the case you better go with the other solution.

Variadic template, function as argument

I would like to use a function as argument in a variadic template, why does the following not work? How do I make it work?
template<typename F, typename... Args>
F test(F f, const Args&&... args) {
return f(std::forward<Args>(args)...);
}
int simple(int i) {
return i;
}
int main()
{
std::cout << test(simple, 2); // error, 'std::forward': none of the 2 overloads could convert all the argument types
}
There are a couple of problems with your code.
First of all, you should use forwarding references, so you need to change const Args&&... to Args&&....
Then, test does not have to return F. So it is reasonable to use decltype(auto) here.
In addition to that, it makes sense to forward f too.
The fixed version might look like this:
template<typename F, typename... Args>
decltype(auto) test(F&& f, Args&&... args) {
return std::forward<F>(f)(std::forward<Args>(args)...);
}
WANDBOX EXAMPLE
The first problem is the return type. Your test function returns F which is a function pointer. Instead change it to auto to automatically deduce the return type.
The second issue is that std::forward requires a non-const reference.
You might use trailing return type:
template<typename F, typename... Args>
auto test(F f, Args&&... args) -> decltype(f(std::forward<Args>(args)...)) {
return f(std::forward<Args>(args)...);
}
But decltype(auto) (C++14 required) is a simpler solution:
template<typename F, typename... Args>
decltype(auto) test(F f, Args&&... args) {
return f(std::forward<Args>(args)...);
}

Invoke a function/functor with parameters more than arguments

I'd like to write a template function which can invoke a function with given parameters.
For instance, I can write a simple invoke function:
template<class F, class... Args>
inline auto invoke(F &&func, Args&&... args) -> decltype(auto)
{
return std::forward<F>(func)(std::forward<Args>(args)...);
}
This invoke accepts same count of parameter which f requires. However, I want to this template function allow additional unused parameters.
That is, I want to write some code like:
auto f = [] (auto a) {...};
invoke(f, 1, 2, 3);
Here, f accepts only one parameter so, I wish invoke ignore other parameters except the first one.
This can be accomplished very easily by get arity of the lambda unless the lambda is generic.
Since f here is generic lambda, as far as I know, there's no general way to figure out arity of f without explicit instantiation of its template operator()<...>.
How can I wirte my invoke?
One possibility:
#include <utility>
#include <cstddef>
#include <tuple>
template <std::size_t... Is, typename F, typename Tuple>
auto invoke_impl(int, std::index_sequence<Is...>, F&& func, Tuple&& args)
-> decltype(std::forward<F>(func)(std::get<Is>(std::forward<Tuple>(args))...))
{
return std::forward<F>(func)(std::get<Is>(std::forward<Tuple>(args))...);
}
template <std::size_t... Is, typename F, typename Tuple>
decltype(auto) invoke_impl(char, std::index_sequence<Is...>, F&& func, Tuple&& args)
{
return invoke_impl(0
, std::index_sequence<Is..., sizeof...(Is)>{}
, std::forward<F>(func)
, std::forward<Tuple>(args));
}
template <typename F, typename... Args>
decltype(auto) invoke(F&& func, Args&&... args)
{
return invoke_impl(0
, std::index_sequence<>{}
, std::forward<F>(func)
, std::forward_as_tuple(std::forward<Args>(args)...));
}
DEMO
Here's a code I've written for my needs based on Piotr's answer:
template <std::size_t... Is, typename F, typename Tuple>
void invoke_impl(
std::index_sequence<Is...>, F&& f, Tuple&& args,
std::enable_if_t<std::is_invocable_v<F, std::tuple_element_t<Is, Tuple>...>,
void>* = nullptr)
{
std::invoke(std::forward<F>(f), std::get<Is>(args)...);
}
template <std::size_t... Is, typename F, typename Tuple>
void invoke_impl(
std::index_sequence<Is...>, F&& f, Tuple&& args,
std::enable_if_t<
!std::is_invocable_v<F, std::tuple_element_t<Is, Tuple>...>, void>* =
nullptr)
{
static_assert(sizeof...(Is) > 0, "Not invocable with arguments supplied");
if constexpr (sizeof...(Is) > 0)
{
invoke_impl(std::make_index_sequence<sizeof...(Is) - 1>(),
std::forward<F>(f), std::move(args));
}
}
// invokes function with possibly too many parameters provided
template <typename F, typename... Args>
void invoke(F&& f, Args&&... args)
{
invoke_impl(std::make_index_sequence<sizeof...(Args)>(), std::forward<F>(f),
std::forward_as_tuple(std::forward<Args>(args)...));
}
It is a little bit improved:
it leverages std::invoke so it works with more use cases, like pionter to members
it matches parameters count starting from sizeof...(Args) so chooses better matched operator() overload
Here's a demo:
struct test
{
void foo()
{
std::cout << "foo" << std::endl;
}
void operator()()
{
std::cout << "operator()()" << std::endl;
}
void operator()(float)
{
std::cout << "operator()(float)" << std::endl;
}
};
int main()
{
test obj;
invoke(&test::foo, &obj, 1, 2, 3); // foo
invoke(obj); // operator()()
invoke(obj, 1, 2, 3); // operator()(float)
// invoke(5); // assert failed
}
Here's a live demo

Get the result type of a function in c++11

Consider the following function in C++11:
template<class Function, class... Args, typename ReturnType = /*SOMETHING*/>
inline ReturnType apply(Function&& f, const Args&... args);
I want ReturnType to be equal to the result type of f(args...)
What do I have to write instead of /*SOMETHING*/ ?
I think you should rewrite your function template using trailing-return-type as:
template<class Function, class... Args>
inline auto apply(Function&& f, const Args&... args) -> decltype(f(args...))
{
typedef decltype(f(args...)) ReturnType;
//your code; you can use the above typedef.
}
Note that if you pass args as Args&&... instead of const Args&..., then it is better to use std::forward in f as:
decltype(f(std::forward<Args>(args)...))
When you use const Args&..., then std::forward doesn't make much sense (at least to me).
It is better to pass args as Args&&... called universal-reference and use std::forward with it.
It doesn't need to be a template parameter, since it isn't used for overload resolution. Try
template<class Function, class... Args>
inline auto apply(Function&& f, const Args&... args) -> decltype(f(std::forward<const Args &>(args)...));
There are situations where std::result_of is more useful. For example, say you want to pass this function:
int ff(int& out, int in);
and inside apply() call it like so
int res;
f(res, args...);
then I wouldn't know how to use decltype, because I have no int lvalue reference at hand. With result_of, you don't need variables:
template<class Function, class... Args>
typename std::result_of<Function(const Args&...)>::type apply(Function&& f, const Args&... args)
{
typedef typename std::result_of<F(const Args&...)>::type ReturnType;
// your code
}

Partial specialization of a template

Consider:
template <typename Function, typename ...Args>
auto wrapper(Function&& f, Args&&... args) -> decltype(f(args...)) {
//...
}
Is there a way to partially specialize the above template for all the cases where decltype(f(args...)) is a pointer?
EDIT:
I think it can be done with an template helper class which takes decltype(f(args...)) as template argument, and specialize the helper class. If you know better solutions let me know.
An SFINAE-based solution:
#include <type_traits>
template<
typename Functor
, typename... Args
, typename Result = decltype(std::declval<Functor&>()(std::declval<Args>()...))
, typename std::enable_if<
std::is_pointer<Result>::value
, int
>::type = 0
>
Result wrapper(Functor&& functor, Args&&... args)
{ /* ... */ }
template<
typename Functor
, typename... Args
, typename Result = decltype(std::declval<Functor&>()(std::declval<Args>()...))
, typename std::enable_if<
!std::is_pointer<Result>::value
, int
>::type = 0
>
Result wrapper(Functor&& functor, Args&&... args)
{ /* ... */ }
You can adapt the test (here, std::is_pointer<Result>) to your needs.
As you see the return type is not a template argument or part of the arguments, so you cannot overload nor specialize. Dispatching on a helper is your best option.
#include <type_traits>
template<typename Func, typename... Args>
void func_impl(Func&& f, Args&&... args, std::true_type)
-> decltype(func_impl(std::forward<Args>(args)...))
{ }
template<typename Func, typename... Args>
void func_impl(Func&& f, Args&&... args, std::false_type)
-> decltype(func_impl(std::forward<Args>(args)...))
{ }
template<typename Func, typename... Args>
auto func(Func&& f, Args&&... args)
-> decltype(func_impl(std::forward<Func>(f), std::forward<Args>(args)...))
{ return func_impl(std::forward<Func>(f), std::forward<Args>(args)...,
std::is_pointer<decltype(f(std::forward<Args>(args)...))>::type); }
It seems a little odd to me to take the function by rvalue reference though and you also omit the forwarding in your original example.
Another possible solution could be a template default argument and overload on that. But that wouldn't work well with the argument list.