how could one do this in c++ today without using two separate holders?
typedef std::function<void(int a, int b)> f1;
typedef std::function<void(int a)> f2;
std::vector<f1> m;
void add(f1 f)
{
m.push_back(f);
}
void add(f2 f)
{
// add one more (unused) parameter to f2 so we can add f2 to f1 vector holder?
}
can we somehow overload f1 function to include different set of parameters?
could this be solved by variadic templates nowdays or something similar?
Create a new lambda matching the new signature and add that instead:
void add(f2 f)
{
m.push_back( [g = std::move(f)](int a, int /* unused */){ g(a); } );
}
This wraps a std::function in a lambda that ignores any extra args:
template<class R, class...Args>
auto ignore_extra_args( std::function<R(Args...)> f ) {
return [f = std::move(f)](Args...args, auto&&...)->R{
return f(std::forward<Args>(args)...);
};
}
it gets trickier if we don't want that needless layer of type erasure.
You need to find the longest prefix of Args... which you can invoke a given object f with, then invoke f with it. This involves some tricky metaprogramming.
It is far easier if you ask the caller to pass in a signature:
template<class Sig>
struct ignore_extra_args_helper;
template<class R, class...Args>
struct ignore_extra_args_helper<R(Args...)> {
template<class F>
auto operator()( F&& f ) {
return [f = std::forward<F>(f)](Args...args, auto&&...)->R{
return f(std::forward<Args>(args)...);
};
}
};
template<class Sig, class F>
auto ignore_extra_args( F&& f ) {
return ignore_extra_args_helper<Sig>{}(std::forward<F>(f));
}
which saves on possible overhead.
template<class F, decltype(std::declval<F const&>()(1,1))* =nullptr>
void add(F&& f) {
m.push_back(std::forward<F>(f));
}
template<class F, class...Unused>
void add(F&& f, Unused&&...) {
add( ignore_extra_args<void(int)>(std::forward<F>(f)) );
}
live example
Related
I need a function My_func that works like this
auto f = [](const std::tuple<string, double>& t) { return std::get<0>(t); };
assert(My_func(f)("Hello", 8.5) == f({"Hello", 8.5}));
Now i have
template <class F>
constexpr auto My_func(F&& f) {
return [f](auto&& args...) { return std::forward<F>(f)(args); };
}
But it doesn't work.What should i fix?
First of all you need My_func to be syntactically valid. You have a pack args that is not expanded in the lambda. Then you need to mention tuple somewhere. C++ is not psychic.
Luckily, there exists std::forward_as_tuple that does exactly what you need here
template <class F>
constexpr auto My_func(F&& f) {
return [f = std::forward<F>(f)](auto&& args...) { return f(std::forward_as_tuple(args...)); };
}
template <class F>
constexpr auto My_func(F&& f)
{
return [f = std::forward<F>(f)](auto&&... args) {
return f(std::make_tuple(std::forward<decltype(args)>(args)...));
};
}
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);
I have multiple std::function. Each of them have different input and output, and the input of one std::function might be the output of another std::function, which means that "serial" convert from one to another.
Maybe I can't describe it clear enough. Let code talks
std::function<bool(double)> combine(std::function<int(double)> convert1
, std::function<char(int)> convert2
, std::function<bool(char)> convert3)
{
return std::bind(convert1, convert2, convert3)//error. A function directly convert [double] to [bool] using convert1, convert2, convert3
}
Here is very simple code which I already remove the pointless code and show the core of my meaning.
So you can see convert1 do conversion from double to int, convert2 do conversion from int to char and convert3 do conversion from char to bool. Now I need to combine them together and so that I can directly convert double to bool.
And you know, I am not really want to convert double to bool. It's only for test.
One option to implement this is that write a help function:
bool helper(double d
, std::function<int(double)> convert1
, std::function<char(int)> convert2
, std::function<bool(char)> convert3)
{
return convert3(convert2(convert1(d)));
}
std::function<double(bool)> combine(std::function<int(double)> convert1
, std::function<char(int)> convert2
, std::function<bool(char)> convert3)
{
return helper;
}
But it's ugly code and maybe I use this conversion in a common way, which means that I should write this helper for all kind of my conversion.
So, is there a directly way to combine these function together?
you can use lambda expression to do this.
std::function<bool(double)> combine(std::function<int(double)> convert1
, std::function<char(int)> convert2
, std::function<bool(char)> convert3)
{
return [=](double d){return convert3(convert2(convert1(d)));}
}
Or you can use lambda directly in your code and do not use this combine function at all, also it would be more clear what happened.
If you still want use combine function and want a more generic one, maybe you can try something like this. (just a simple example)
template<typename Converter>
auto combineX(Converter converter){
return converter;
}
template<typename Converter, typename ...Converters>
auto combineX(Converter converter, Converters... converters){
return [converter,remain = combineX(converters...)](auto x){return remain(converter(x));};
}
Creating a simple type traits to extract the input type of the last function
template <typename, typename...>
struct lastFnType;
template <typename F0, typename F1, typename ... Fn>
struct lastFnType<F0, F1, Fn...>
{ using type = typename lastFnType<F1, Fn...>::type; };
template <typename T1, typename T2>
struct lastFnType<std::function<T2(T1)>>
{ using type = T1; };
you can transform the apple apple's solution (+1) in a more general variadic template recursive solution
template <typename T1, typename T2>
std::function<T1(T2)> combine (std::function<T1(T2)> conv)
{ return conv; }
template <typename T1, typename T2, typename T3, typename ... Fn>
std::function<T1(typename lastFnType<std::function<T2(T3)>, Fn...>::type)>
combine (std::function<T1(T2)> conv1, std::function<T2(T3)> conv2,
Fn ... fn)
{
using In = typename lastFnType<std::function<T2(T3)>, Fn...>::type;
return [=](In const & in){ return conv1(combine(conv2, fn...)(in)); };
}
But observe that the order of the converter is inverted (call with last used converter first; so combine(convert3, convert2, convert1))
The following is a full example
#include <functional>
template <typename, typename...>
struct lastFnType;
template <typename F0, typename F1, typename ... Fn>
struct lastFnType<F0, F1, Fn...>
{ using type = typename lastFnType<F1, Fn...>::type; };
template <typename T1, typename T2>
struct lastFnType<std::function<T2(T1)>>
{ using type = T1; };
template <typename T1, typename T2>
std::function<T1(T2)> combine (std::function<T1(T2)> conv)
{ return conv; }
template <typename T1, typename T2, typename T3, typename ... Fn>
std::function<T1(typename lastFnType<std::function<T2(T3)>, Fn...>::type)>
combine (std::function<T1(T2)> conv1, std::function<T2(T3)> conv2,
Fn ... fn)
{
using In = typename lastFnType<std::function<T2(T3)>, Fn...>::type;
return [=](In const & in){ return conv1(combine(conv2, fn...)(in)); };
}
int fn1 (double d)
{ return d*2.0; }
char fn2 (int i)
{ return i+3; }
bool fn3 (char c)
{ return c == 'a'; }
int main ()
{
std::function<int(double)> f1 { fn1 };
std::function<char(int)> f2 { fn2 };
std::function<bool(char)> f3 { fn3 };
auto cmb = combine(f3, f2, f1);
bool b { cmb(3.2) };
}
You may do:
template <typename T, typename F>
decltype(auto) apply(T&& t, F&& f)
{
return std::forward<F>(f)(std::forward<T>(t));
}
template <typename T, typename F, typename... Fs>
decltype(auto) apply(T&& t, F&& f, Fs&&... fs)
{
return apply(std::forward<F>(f)(std::forward<T>(t)), std::forward<Fs>(fs)...);
}
with usage:
apply(4,
[](int i) { return i * 10; },
[](auto i) {return i + 2;},
[](auto n){ return n / 10.f; })
Demo
How the compiler interpret the symbol _1, and how the binding take place?
Consider the following example:
class A {
public:
boost::function<void (int x)> g;
};
class B {
public:
B() {}
static void foo(int i) { cout << "Hack: " << i <<endl; }
};
int main() {
A a;
a.g = boost::bind(B::foo,_1);
a.g(2);
return 0;
}
What magic happens internally in the line boost::bind(B::foo,_1);?
And how _1 is maped to the argument passed in the next line a.g(2);?
Output: Hack: 2
I will explain to the best of my ability. First and foremost, _1 is nothing but a global variable. There is nothing special about it in this regard, and it could be named anything else as well - placeholder1, or SergeyA. However, name like _1 is short, has well-understood meaning, and begins with _, which reduces likelihood of it clashing with other global names in the program.
The magic is in the type of this variable. It has a special type, which is reflected in generated bind* object. Later, when operator() is called, the type is recognized to take an argument from operator() arguments.
Here is some illustrating C++-like pseudocode, which is not correct, but is illustrative:
template<class F, class... ARG>
struct bound {
bound(F f, ARGS&&... args) : bound_args(args...), functor(f) { }
std::tuple<ARG...> bound_args;
template<class... T>
void operator()(T&&... args);
F f;
};
template<class F, class... T>
auto bind(F f, T&& args) {
return bound<std::remove_reference_t<T>...>(f, args...);
}
Now, let's introduce a placeholder type.
template<size_t N>
struct placeholder {
enum { position = N; };
template<class...T>
auto operator()(T&&... args) {
return std::get<position>(std::make_tuple(arg...));
}
};
placeholder<0> _1;
placeholder<1> _2;
So far so good. Now, let's see how the operator() actually works on bound object:
template<class... BOUND_ARGS>
template<class... CALL_ARGS>
void bound_object<BOUND_ARGS...>::operator() (CALL_ARGS&&... args) {
call_impl(args..., make_index_sequence<sizeof...(BOUND_ARGS)>{});
}
make_index_sequence here is needed to extract tuple values into function arguments, so do not pay too much attention to it. And here is call_impl;
template<class... BOUND_ARGS>
template<class... CALL_ARGS, size_t... ix>
void bound_object<BOUND_ARGS...>::call_impl(CALL_ARGS&&... args, std::index_sequence<ix...>) {
f(to_arg().(std::get<ix>(bound_args), args...)...);
}
And the last piece of puzzle is to_arg:
template<class B, class... ARGS>
auto to_arg(B&& b, ARGS... args) {
return b;
}
template<class... ARGS>
auto to_arg(placeholder<0> p, ARGS&&... args) {
return p(args);
}
template<class... ARGS>
auto to_arg(placeholder<1> p, ARGS&&... args) {
return p(args);
}
The whole of to_arg here is to give you either the bound argument or one of the supplied arguments, based on the bound argument type. In my example above, I used 3 overloads since you can partially specialize a function, but of course, it would make more sense to put it in a class and partially specialize the class.
I have the following template specializations which wrap C++ functions to Lua:
template<class ...Args>
struct Wrapper<void (*)(Args...)> {
using F = void (*)(Args...);
static int f (lua_State *L)
{
Lua lua(L);
// Grab the function pointer.
F f = (F) lua_touserdata(L, lua_upvalueindex(1));
// Build a tuple of arguments.
auto args = lua.CheckArgs<1, Args...>();
// Apply the function to the tuple.
FunctionPointer<F> fp(f);
fp.Apply(args);
return 0;
}
};
template<class R, class ...Args>
struct Wrapper<R (*)(Args...)> {
using F = R (*)(Args...);
static int f (lua_State *L)
{
Lua lua(L);
// Grab the function pointer.
F f = (F) lua_touserdata(L, lua_upvalueindex(1));
// Build a tuple of arguments.
auto args = lua.CheckArgs<1, Args...>();
// Apply the function to the tuple.
FunctionPointer<F> fp(f);
lua.Push( fp.Apply(args) );
return 1;
}
};
Notice how they differ rather minimally. In the first specialization, FunctionPointer<F>::Apply returns void. In the second, it's result is pushed onto the Lua stack.
Can I combine these two specializations into one?
I realize this may seem pedantic, but I have had to write a lot of these wrappers elsewhere in my code, because of variations in the type of the function being wrapper (free function, or PMF, const or not). I have a total of 14 such specializations.
Here are two more which differ only by whether the PMF is const or not:
template <typename Self, typename ...Args>
struct MethodWrapper<void (Self::*)(Args...) >
{
using F = void (Self::*)(Args...);
static int f (lua_State *L)
{
Lua lua(L);
F f = *(F *)lua_touserdata(L, lua_upvalueindex(1));
Self* self = lua.CheckPtr<Self>(1);
auto args = lua.CheckArgs<2, Args...>();
FunctionPointer<F> fp(f);
try {
fp.Apply(self, args);
} catch(std::exception& e) {
luaL_error(L, e.what());
}
return 0;
}
};
template <typename R, typename Self, typename ...Args>
struct MethodWrapper<R (Self::*)(Args...) const >
{
// exactly the same as above
};
Can I avoid this cut and paste? (Without using macros though)
Related, but suffers from the same number of required specializations: How to use variadic templates to make a generic Lua function wrapper?
You should be able to make a generic functor which takes fp, args, and lua, and calls lua.Push(), with a partial specialization for when R is void which just invokes the function and ignores the (void) result. You would then invoke it like this:
ApplyAndPushIfNotVoid<R>()(lua, fp, args);
It's definitely possible to eliminate all that repetitive template specialization. In fact, for a one-off branching case, like in your free-function struct Wrapper, you don't even need to write a specialization to hide it -- just use std::is_void from type_traits:
template<typename R, typename ...Args>
struct Wrapper
{
using F = R (*)(Args...);
static int f (lua_State *L, F f)
{
// ...
FunctionPointer<F> fp {f};
if (std::is_void<R>::value)
{
fp.Apply(args);
return 0;
}
else
{
lua.Push( fp.Apply(args) );
return 1;
}
}
};
The compiler will optimize out one of the branches depending on how it gets instantiated.
There is a slight wrinkle though, when the return type is R = void the falsey branch still gets type-checked during instantiation which results in the body being ill-formed.
Using template specialization like in the other answer is one obvious solution. There is an alternative workaround: have FunctionPointer<F>::Apply return a dummy void_type when R = void. For example using std::conditional, FunctionPointer can be modified to work like:
template <typename F>
class FunctionPointer
{
template <typename R, typename ...Args>
static R func_return( R(*)(Args...) )
{ return {}; }
using R_ = decltype( func_return( (F)nullptr ) );
struct void_type {};
public:
F f;
using R = typename std::conditional<std::is_void<R_>::value,
void_type, R_>::type;
template <typename ...Args>
R Apply(std::tuple<Args...> &args)
{
// ...
return {};
}
};
IDEone Demo with external dependent types stubbed out.
For the MethodWrapper, I would identify the different 'traits' and aspects it needs from the member pointer and extract all those and hide it behind some trait class. Let's call it PMF_traits:
template <typename T, typename ...Args>
struct PMF_traits
{
private:
using T_traits = decltype( PMF_trait_helper( (T)nullptr ) );
public:
using class_type = typename T_traits::class_type;
using return_type = typename T_traits::return_type;
static const bool const_member = T_traits::const_member;
using type = T;
};
The PMF_trait_helper itself is just an empty function to help deduce and extract type information out of PMF. Here is where the const and non-const PMF is handled. That information is captured using PMF_trait_detail and passed back up to PMF_traits.
template <typename R, typename Class, bool Is_Const>
struct PMF_trait_detail
{
using class_type = Class;
using return_type = R;
static const bool const_member = Is_Const;
};
template <typename R, typename Class, typename ...Args>
PMF_trait_detail<R, Class, false> PMF_trait_helper( R (Class::*)(Args...) )
{ return PMF_trait_detail<R, Class, false> (); }
template <typename R, typename Class, typename ...Args>
PMF_trait_detail<R, Class, false> PMF_trait_helper( R (Class::*)(Args...) const)
{ return PMF_trait_detail<R, Class, true> (); }
With that setup MethodWrapper no longer needs to handle const non-const cases separately
template <typename PMF, typename ...Args>
struct MethodWrapper
{
typedef typename PMF_traits<PMF>::class_type Self;
int f (lua_State *L)
{
// ...
FunctionPointer<PMF> fp { (PMF) lua_touserdata(L, lua_upvalueindex(1)) };
Self *self = lua.CheckPtr<Self>(1);
// ...
try
{
// Almost like 'Wrapper' above
// handle void and non-void case etc.
if (std::is_void< typename PMF_traits<PMF>::return_type >::value)
{
fp.Apply(self, args);
return 0;
}
else { // ... }
}
catch(std::exception& e)
{
return luaL_error(L, e.what());
}
}
};
Note I didn't capture the variadic arguments in the PMF_traits just to keep the template complexity and syntactic verbiage down but it should be possible to encode and save this info too using std::tuple if you need that.
Using this technique you should be able to refactor and significantly reduce the number of specializations you need.