related post: How to combine std::bind(), variadic templates, and perfect forwarding?
Is there a way to bind a function with variadic tuples ? Here incorrect code indicating the intent:
// t is an instance of T
auto f = std::bind(&T::iterate,t,???);
// args is an instance of std::tuple<Args...> args;
std::apply(f,args);
(note: I am unsure "variadic tuple" to be the right terminology. Looking forward editing the post with your correction)
Since C++20 you can use std::bind_front:
template<class T>
void print (T val) {
std::cout << val << std::endl;
}
struct T {
template<class ... Args>
void iterate(Args... args) {
int temp[] = { (print(args),0)... };
}
};
// all happens here
template<class ... Args>
void foo(const tuple<Args...>& args) {
T t;
auto f = std::bind_front(&T::iterate<Args...>,&t);
std::apply(f,args);
}
// the call
int i = 1;
foo(std::make_tuple(i,i+1,"bind is cool"));
If you want to use old std::bind, you can provide your own placeholders to be generated from pack:
template<int N>
struct MyPlaceholder {};
namespace std {
template<int N>
struct is_placeholder<MyPlaceholder<N>> : public integral_constant<int, N> {};
}
template<class ... Args, size_t ... Indices>
void foo2helper(const tuple<Args...>& args, std::index_sequence<Indices...>) {
T t;
auto f = std::bind(&T::iterate<Args...>,&t, (MyPlaceholder<Indices+1>{})...);
std::apply(f,args);
}
template<class ... Args>
void foo2(const tuple<Args...>& args) {
foo2helper(args, std::make_index_sequence<sizeof...(Args)>{});
}
// the call
foo2(std::make_tuple(2.34,"only bind"));
Live demo
Don't use bind, use a lambda instead:
auto f = [&t](auto... args){ t.iterate(args...); };
std::apply(f, args);
If you want perfect forwarding, that would look like:
auto f = [&t](auto&&... args){ t.iterate(std::forward<decltype(args)>(args)...); };
std::apply(f, args);
Related
Here some code with holes:
template<typename... Args>
class A
{
typedef function_type = void(*)(Args...);
public:
void set_args(Args&& ... args)
{
// something magic manages to encapsulate
// args in instance of A
}
void apply_args(function_type function)
{
// something magic manages to "retrieve"
// the encapsulated args
function(std::forward<Args>(args)...);
}
};
Would that be somehow possible ?
You can store your template arguments in class data member of std::tuple type and the use std::apply in order to apply stored arguments to provided function.
So, let's say you have an Action class like this:
template <typename... Args>
class Action {
std::tuple<Args...> args_;
public:
Action() = default;
Action(Args&&... args)
: args_(std::forward<Args>(args)...)
{}
void args(Args&&... args) {
args_ = std::make_tuple<Args...>(std::forward<Args>(args)...);
}
template <typename F>
void apply(F&& fun) {
std::apply(std::forward<F&&>(fun), args_);
}
};
where you set arguments through constructor Action action(1, 2, 3); or through separate function action.set(3, 2, 1);.
Then your main function can look like this:
int main() {
Action action(1, 2);
action.apply([](int a, int b) {
std::cout << "a + b = " << (a + b) << std::endl;
});
return 0;
}
Check live example
You can make use of std::tuple and std::apply
#include <iostream>
#include <tuple>
#include <functional>
#include <string>
template <typename... Ts>
class A
{
private:
std::function<void (Ts...)> f;
std::tuple<Ts...> args;
public:
template <typename F>
A(F&& func, Ts&&... args)
: f(std::forward<F>(func)),
args(std::make_tuple(std::forward<Ts>(args)...))
{}
void Invoke()
{
std::apply(f, args);
}
};
template <typename F, typename... Args>
A<Args...> Create(F&& f, Args&&... args)
{
return A<Args...>(std::forward<F>(f), std::forward<Args>(args)...);
}
int main()
{
auto helloWorld = Create([] (std::string a, std::string b) { std::cout << a << ", " << b; }, std::string("Hello"), std::string("World!"));
helloWorld.Invoke();
}
For a set of N functions fs... each taking only a single argument, I would like to create an object which has a call operator taking N arguments args..., calls all functions fs(args)... and returns outputs as a tuple.
The basic class would look something like this. I have marked the places I do not know how to implement with ???.
template <class... Fs>
struct merge_call_object {
merge_call_object(Fs... _fs)
: fs(std::move(_fs)...) {}
template <class... Args>
auto operator()(Args &&... args) -> decltype(???){
???
}
std::tuple<Fs...> fs;
};
The expected usage of this object would be:
auto f1 = [](double x){ return 2*s; };
auto f2 = [](std::string const& s){ return s+" World!"; };
auto mco = merge_call_object{f1,f2};
// The following should yield std::tuple{42, "Hello World!"}
auto out = mco(21, "Hello ");
So far so good, doing the above is "easy" but I want that overloading for mco works as expected i.e. the following should compile and pass
static_assert(std::is_invocable_v<decltype(mco), double, std::string> == true);
static_assert(std::is_invocable_v<decltype(mco), double, double> == false);
The biggest challenge I see is how implement correctly the SFINAE -> decltype(???).
This question is inspired by the recent talk from CppCon Overloading: The Bane of All Higher-Order Functions, around 6:40 he talks about how to wrap a function into a lambda.
My implementation without the correct overload set, plus a small test on perfect forwarding.
#include <iostream>
#include <tuple>
#include <utility>
namespace detail {
template <std::size_t... I>
constexpr auto integral_sequence_impl(std::index_sequence<I...>) {
return std::make_tuple((std::integral_constant<std::size_t, I>{})...);
}
template <std::size_t N, typename Indices = std::make_index_sequence<N>>
constexpr auto integral_sequence = integral_sequence_impl(Indices{});
template <std::size_t N, typename Fun>
constexpr decltype(auto) apply_sequence(Fun &&fun) {
return std::apply(std::forward<Fun>(fun), detail::integral_sequence<N>);
}
} // namespace detail
template <class... Fs>
struct merge_call_object {
merge_call_object(Fs... _fs)
: fs(std::move(_fs)...) {}
template <class... Args>
auto operator()(Args &&... args) {
constexpr int N = sizeof...(Fs);
auto f = [&](auto I) { return std::get<I>(fs); };
auto arg = [&](auto I) -> decltype(auto) {
return std::get<I>(std::forward_as_tuple(std::forward<Args>(args)...));
};
return detail::apply_sequence<N>(
[&](auto... Is) { return std::forward_as_tuple(f(Is)(arg(Is))...); });
}
std::tuple<Fs...> fs;
};
struct Screamer {
Screamer() { std::cout << "Constructor!" << std::endl; }
Screamer(Screamer &&s) { std::cout << "Move constructor!" << std::endl; }
Screamer(Screamer const &s) { std::cout << "Copy constructor!" << std::endl; }
};
int main() {
auto f1 = [](auto &&x) -> decltype(auto) {
std::cout << "Calling f1" << std::endl;
return std::forward<decltype(x)>(x);
};
auto f2 = [](auto &&x) -> decltype(auto) {
std::cout << "Calling f2" << std::endl;
return std::forward<decltype(x)>(x);
};
auto mco = merge_call_object{f1, f2};
auto [s1, s2] = mco(Screamer{}, Screamer{});
return 0;
}
Since you have a direct one argument, one function mapping, all you really need is std::apply:
template <class... Args>
auto operator()(Args&&... args) {
return std::apply([&](Fs&... fs){
return std::tuple(fs(std::forward<Args>(args))...);
}, fs);
}
This will decay all of the types (that is, if some function/argument pair actually returns an int&, this will give you an int in that spot instead). This also isn't SFINAE-friendly.
A solution that is both SFINAE-friendly and maintains references just needs an extra dash of fold-expression:
template <class... Args,
std::enable_if_t<(std::is_invocable_v<Fs&, Args> && ...), int> = 0>
auto operator()(Args&&... args) {
return std::apply([&](Fs&... fs){
return std::tuple<std::invoke_result_t<Fs&, Args>...>(
fs(std::forward<Args>(args))...);
}, fs);
}
You have to use auto f() -> decltype(RET) { return RET; } way (Macro can be used to avoid the boiler plate :-/ and we can also handle noexcept).
Something like:
template <class... Fs>
struct merge_call_object {
private:
std::tuple<Fs...> fs;
private:
template <std::size_t... Is, typename Tuple>
auto call(std::index_sequence<Is...>, Tuple&& tuple)
-> decltype(std::make_tuple(std::get<Is>(fs)(std::get<Is>(std::forward<Tuple>(tuple)))...))
{
return std::make_tuple(std::get<Is>(fs)(std::get<Is>(std::forward<Tuple>(tuple)))...);
}
public:
merge_call_object(Fs... _fs)
: fs(std::move(_fs)...) {}
template <class... Args>
auto operator()(Args &&... args)
-> decltype(call(std::index_sequence_for<Fs...>(), std::forward_as_tuple(std::forward<Args>(args)...)))
{
return call(std::index_sequence_for<Fs...>(), std::forward_as_tuple(std::forward<Args>(args)...));
}
};
Demo
Given two or more example functions, is it possible to write templated code which would be able to deduce the arguments of a function provided as a template parameter?
This is the motivating example:
void do_something(int value, double amount) {
std::cout << (value * amount) << std::endl;
}
void do_something_else(std::string const& first, double & second, int third) {
for(char c : first)
if(third / c == 0)
second += 13.7;
}
template<void(*Func)(/*???*/)>
struct wrapper {
using Args = /*???*/;
void operator()(Args&& ... args) const {
Func(std::forward<Args>(args)...);
}
};
int main() {
wrapper<do_something> obj; //Should be able to deduce Args to be [int, double]
obj(5, 17.4); //Would call do_something(5, 17.4);
wrapper<do_something_else> obj2; //Should be able to deduce Args to be [std::string const&, double&, int]
double value = 5;
obj2("Hello there!", value, 70); //Would call do_something_else("Hello there!", value, 70);
}
In both uses of /*???*/, I am trying to work out what I could put there that would enable this kind of code.
The following doesn't appear to work, due to Args not being defined before its first use (along with what I have to assume are numerous syntax errors besides), and even if it did, I'm still looking for a version that doesn't require explicit writing of the types themselves:
template<void(*Func)(Args ...), typename ... Args)
struct wrapper {
void operator()(Args ...args) const {
Func(std::forward<Args>(args)...);
}
};
wrapper<do_something, int, double> obj;
With C++17 we can have auto template non-type parameters which make possible the Wrapper<do_something> w{} syntax 1).
As for deducing Args... you can do that with a specialization.
template <auto* F>
struct Wrapper {};
template <class Ret, class... Args, auto (*F)(Args...) -> Ret>
struct Wrapper<F>
{
auto operator()(Args... args) const
{
return F(args...);
}
};
Wrapper<do_something> w{};
w(10, 11.11);
1) Without C++17 it's impossible to have the Wrapper<do_something> w{} nice syntax.
The best you can do is:
template <class F, F* func>
struct Wrapper {};
template <class Ret, class... Args, auto (*F)(Args...) -> Ret>
struct Wrapper<Ret (Args...), F>
{
auto operator()(Args... args) const
{
return F(args...);
}
};
Wrapper<declype(do_something), do_something> w{};
With C++17, you can do this:
template <auto FUNC, typename = decltype(FUNC)>
struct wrapper;
template <auto FUNC, typename RETURN, typename ...ARGS>
struct wrapper<FUNC, RETURN (*)(ARGS...)> {
RETURN operator()(ARGS ...args) {
return FUNC(args...);
}
};
I've learned this technique from W.F.'s answer
Further improvement of C++17 version: less template parameters and proper noexcept annotation:
template<auto VFnPtr> struct
wrapper;
template<typename TResult, typename... TArgs, TResult ( * VFnPtr)(TArgs...)> struct
wrapper<VFnPtr>
{
TResult
operator ()(TArgs... args) const noexcept(noexcept((*VFnPtr)(::std::forward<TArgs>(args)...)))
{
return (*VFnPtr)(::std::forward<TArgs>(args)...);
}
};
With C++11 you can consider a templated make_wrapper helper function. However, with this approach the function pointer is not a template parameter. Instead, the function pointer is "carried" by the non-static data member called f_ in the following example:
#include <iostream>
void do_something(int value, double amount) {
std::cout << (value * amount) << std::endl;
}
void do_something_else(std::string const& first, double & second, int third) {
for(char c : first)
if(third / c == 0)
second += 13.7;
}
template<class Ret, class... Args>
using function_pointer = Ret(*)(Args...);
template<class Ret, class... Args>
struct wrapper {
using F = function_pointer<Ret, Args...>;
F f_;
explicit constexpr wrapper(F f) noexcept : f_{f} {}
template<class... PreciseArgs>// not sure if this is required
Ret operator()(PreciseArgs&&... precise_args) const {
return f_(std::forward<PreciseArgs>(precise_args)...);
}
};
template<class Ret, class... Args>
constexpr auto make_wrapper(
function_pointer<Ret, Args...> f
) -> wrapper<Ret, Args...> {
return wrapper<Ret, Args...>(f);
}
int main() {
constexpr auto obj = make_wrapper(do_something);
obj(5, 17.4);
constexpr auto obj2 = make_wrapper(do_something_else);
double value = 5;
obj2("Hello there!", value, 70);
return 0;
}
I am trying to write code to do something similar (code written for demonstration purposes) to this:
template <typename F, typename Args...>
inline auto runFunc(F func) -> foo
{
return foo([func](Args... args) -> std::result_of<F>::type
{
// Do something before calling func
func(args...);
// Do something after call func
});
}
So basically I am trying to write a function that returns an object that takes lambda that matches the templated function type. Obviously this code won't work because I do not have Args... defined. How would I solve this in C++11?
template<class F_before, class F, class F_after>
struct decorate_func_t {
F_before f0;
F f1;
F_after f2;
template<class...Args>
typename std::result_of<F(Args...)>::type operator()(Args&&...args)const{
f0();
auto r = f1(std::forward<Args>(args)...);
f2();
return r;
}
};
template<class F_before, class F, class F_after>
decorate_func_t<F_before, F, F_after>
decorate_func( F_before before, F f, F_after after ){
return {std::move(before), std::move(f), std::move(after)};
}
Then:
template <typename F, typename Args...>
inline auto runFunc(F func) -> foo
{
return foo(decorate_func(
[]{/* Do something before calling func */},
func,
[]{/* Do something after call func */ }
};
}
the lack of auto parameters in C++11 lambdas makes this about the best you can do.
In C++14 this is trivial:
template <class F>
auto runFunc(F func)
{
return foo(
[func](auto&&... args) // ->decltype(auto) maybe
{
// Do something before calling func
auto r = func(decltype(args)(args)...);
// Do something after call func
return r;
}
);
}
note that many nominally C++11 compilers actually support auto parameters on lambdas.
You can use a support structure as in the following example:
#include<type_traits>
#include<cassert>
struct foo {
template<typename F>
foo(F f) { assert(42 == f(42)); }
};
template<typename>
struct S;
template<typename R, typename... Args>
struct S<R(*)(Args...)> {
template <typename F>
static auto runFunc(F func) -> foo
{
return foo{[func](Args... args) -> R
{
// Do something before calling func
auto r = func(args...);
// Do something after call func
return r;
}};
}
};
template<typename F>
inline auto runFunc(F func) -> foo
{
return S<F>::runFunc(func);
}
int f(int i) { return i; }
int main() {
runFunc(f);
}
For it's not clear to me what's the context of the problem, I'm not sure I got exactly what you were asking for.
I hope the code above can help you.
Still being unsure it this is what you're searching for, I risk posting:
#include <iostream>
struct foo
{
template<typename T>
foo(T lambda)
{
lambda(1, 2);
}
};
template <typename F, typename... Args>
inline typename std::result_of<F>::type runFunc(F func)
{
return foo(
[func](Args... args)
{
std::cout << "Before";
func(args...);
std::cout << "After";
}
);
}
struct print
{
void operator()(int i) const
{
std::cout << i << std::endl;
}
void operator()(int i, int j) const
{
std::cout << i << " " << j << std::endl;
}
};
int main()
{
runFunc<print, int, int>(print());
}
So I wrote a function that composes "sequentially" void lambdas so that I can use them at once in an algorithm:
template <typename F, typename... Fs>
auto lambdaList(F f, Fs... fs)
{
return [=] (auto&... args) { f(args...); lambdaList(fs...)(args...); };
}
template <typename F>
auto lambdaList(F f)
{
return [=] (auto&... args) { f(args...); };
}
It works if I use local lambdas, but not when I use functions in a different namespace:
#include <iostream>
namespace foo {
void a() { std::cout << "a\n"; }
void b() { std::cout << "b\n"; }
}
template <typename F, typename... Fs>
auto lambdaList(F f, Fs... fs)
{
return [=] (auto&... args) { f(args...); lambdaList(fs...)(args...); };
}
template <typename F>
auto lambdaList(F f)
{
return [=] (auto&... args) { f(args...); };
}
int main() {
auto printStarBefore = [] (const std::string& str) {
std::cout << "* " + str;
};
auto printStarAfter = [] (const std::string& str) {
std::cout << str + " *" << std::endl;
};
lambdaList(printStarBefore, printStarAfter)("hi"); // ok
lambdaList(foo::a, foo::b)(); // error
}
The error is no matching function for call to 'lambdaList()' with:
main.cpp:11:56: note: candidate expects at least 1 argument, 0 provided
return [=] (auto&... args) { f(args...); lambdaList(fs...)(args...); };
~~~~~~~~~~^~~~~~~
Why does it sometimes work but sometimes not?
You need to invert your functions:
template <typename F>
auto lambdaList(F f)
{
return [=] (auto&... args) { f(args...); };
}
template <typename F, typename... Fs>
auto lambdaList(F f, Fs... fs)
{
return [=] (auto&... args) { f(args...); lambdaList(fs...)(args...); };
}
As-is, your base case won't be found by unqualified lookup in your recursive case - it can only be found by argument dependent lookup. If the arguments aren't in the same namespace as lambdaList, then it won't be found at all and the recursive step will always call itself. That's the source of your error.
The new ordering allows the base-case lambdaList() to be found by normal unqualified lookup - now it's visible at the point of definition of the recursive lambdaList().
That said, we can do better. Write one function that invokes everything:
template <typename... Fs>
auto lambdaList(Fs... fs) {
using swallow = int [];
return [=](auto const&... args) {
(void)swallow{0,
(void(fs(args...)), 0)...
};
};
}
And now we don't need to worry about any kind of lookup. If you have access to a modern-enough compiler that supports some C++1z features, the above can be greatly reduced with:
template <typename... Fs>
auto lambdaList(Fs... fs) {
return [=](auto const&... args) {
(fs(args...), ...);
};
}
That's downright understandable!