I'd like to generically "pickle" function calls so they can be executed later. The return type of those functions will always be void (for now). Something like this:
template<typename F, typename... Args>
std::function<void()>
pickle(F function, Args&&... args) {
return std::bind(F, args...);
}
The problem is, if args contains a const reference, std::bind tries to copy construct the value, which is not always desired or even valid if the type lacks a copy constructor. How do I forward the arguments in a way that uses std::ref for lvalue references and the normal std::forward for lvalue references?
Example
#include <functional>
class NonCopyable {
public:
NonCopyable() {}
NonCopyable(const NonCopyable&) = delete;
};
template<typename F, typename... Args>
std::function<void()>
pickle(F function, Args&&... args)
{
return std::bind(function, std::forward<Args>(args)...);
}
int main()
{
NonCopyable obj;
auto f = pickle(
[](const NonCopyable&) {},
obj
);
return 0;
}
The above snippet won't compile, complaining about the deleted copy constructor. (I used forward here because someone suggested it, but has since deleted their answer, it seems).
Overloading, yay.
// also does the correct thing for `T const`
template<class T>
std::reference_wrapper<T> maybe_ref(T& v, int){ return std::ref(v); }
// just forward rvalues along
template<class T>
T&& maybe_ref(T&& v, long){ return std::forward<T>(v); }
template<typename F, typename... Args>
std::function<void()>
pickle(F function, Args&&... args) {
return std::bind(function, maybe_ref(std::forward<Args>(args), 0)...);
}
The int/long parameters and 0 argument disambiguate the lvalue case for compilers that find the overloads to be ambiguous, and doesn't do any harm otherwise.
This is a bit ugly (overuse of enable_if), but it works:
template<typename T> typename std::enable_if<
!std::is_lvalue_reference<T>::value, T &&>::type
forward_as_ref(typename std::remove_reference<T>::type &t) {
return static_cast<T &&>(t);
}
template<typename T> typename std::enable_if<
!std::is_lvalue_reference<T>::value, T &&>::type
forward_as_ref(typename std::remove_reference<T>::type &&t) {
return t;
}
template<typename T> typename std::enable_if<
std::is_lvalue_reference<T>::value,
std::reference_wrapper<typename std::remove_reference<T>::type>>::type
forward_as_ref(T t) {
return t;
}
Here's a version using class template specialization instead:
template<typename T> struct forward_as_ref_type {
typedef T &&type;
};
template<typename T> struct forward_as_ref_type<T &> {
typedef std::reference_wrapper<T> type;
};
template<typename T> typename forward_as_ref_type<T>::type forward_as_ref(
typename std::remove_reference<T>::type &t) {
return static_cast<typename forward_as_ref_type<T>::type>(t);
}
template<typename T> T &&forward_as_ref(
typename std::remove_reference<T>::type &&t) {
return t;
}
Related
I am trying to access variables in a struct thru nested member pointers:
#include <iostream>
typedef struct {
int a;
int b;
} bar;
typedef struct {
int c;
bar d;
} baz;
template <typename obj, class C1, class C2, typename T1, typename T2>
T2 test1(const obj& obj_, T1 C1::* field1_, T2 C2::* field2_)
{
return (obj_.*field1_).*field2_;
}
int main()
{
baz myObj;
test1(myObj, &baz::d, &bar::b);
}
How would I turn the function test into a variadic function, so that i can access variables at variable "depths" into the struct?
I've tried to follow the second example in the Function parameter list section here, but am not getting it it seems:
template <typename obj, class ...C, typename... T>
void test2(const obj& obj_, T C...::* field_)
{
// ??
// and what about the function return parameter?
}
int main()
{
baz myObj;
test2(obj,&baz::d,&bar::b);
test2(obj,&baz::c);
}
With this, the definition of test2() already doesn't compile.
Any (latest) version of C++ can be used (with MSVC though).
For tests purpose, here is a complete program on coliru.
Solution
Thanks to Silvio's answer, I was able to solve it. Taking advantage of C++17, it can be made slightly shorter still:
template <typename T, typename S, typename... Ss>
auto inline test2(const T& obj, S field1, Ss... fields)
{
if constexpr (!sizeof...(fields))
return obj.*field1;
else
return test2(obj.*field1, fields...);
}
There may be a cleaner way to do this, but you can certainly take the "throw it at the wall and see what sticks" approach that C++ templates love so much.
template <typename T>
auto test2(const T& obj) -> T {
return obj;
}
template <typename T, typename S, typename... Ss>
auto test2(const T& obj, S field1, Ss... fields)
-> decltype(test2(obj.*field1, fields...)) {
return test2(obj.*field1, fields...);
}
The base case is pretty straightforward. If we don't pass any fields, we just return the original object itself. The recursive case is just that: we recurse. The return type is declared to be... the declared type of the return value. The argument types are simply variables. They'll be instantiated fully as needed. If you pass arguments that don't make sense or don't type check, you'll get some wonderfully ugly error messages.
This requires c++17 support for folding expressions.
namespace utils {
template<class T>struct tag_t{ using type=T; };
template<class...Ts>
using last = typename std::tuple_element_t< sizeof...(Ts)-1, std::tuple<tag_t<Ts>...> >::type;
template<class Lhs, class F>
struct fold_invoker_t;
template<class Lhs, class F>
fold_invoker_t<Lhs, F> fold_invoker(Lhs&&lhs, F&& f);
template<class Lhs, class F>
struct fold_invoker_t {
Lhs lhs;
F f;
template<class Rhs>
auto operator*( Rhs&& rhs )&& {
return fold_invoker(std::forward<F>(f)(std::forward<Lhs>(lhs), std::forward<Rhs>(rhs)), static_cast<F>(f));
}
};
template<class Lhs, class F>
fold_invoker_t<Lhs, F> fold_invoker(Lhs&&lhs, F&& f){ return {std::forward<Lhs>(lhs), std::forward<F>(f)}; }
}
then we write:
template <typename Obj, class ...C, typename... T>
utils::last<Obj, T...> const& test2(const Obj& obj, T C::*... field)
{
auto get_member=[](auto&& elem, auto&& memptr)->decltype(auto){ return elem.*memptr; };
return (utils::fold_invoker( obj, get_member ) * ... * field).lhs;
}
and it is all expanded on that one line.
live example.
No idea if this will work in MSVC's C++17 support.
I am trying to achieve the following:
template<template<typename> bool Function_, typename ... Types_>
constexpr auto find(Tuple<Types_ ... >) noexcept
{
// ...
}
where a possible function could be:
template<typename T>
inline constexpr bool is_pointer_v = is_pointer<T>::value;
so then the usage of find would be:
Tuple<int, char, void *> t;
find<is_pointer_v>(t);
don't worry about the implementation of find, I am just asking about how to do "template < typename > bool Function_" as the bool part is invalid in c++ currently.
any help is appreciated!
EDIT:
here is an example of why I can't pass the "is_pointer" to the function:
template<typename T_>
constexpr auto add_pointer(Type<T_>) noexcept
{ return type_c<T_ *>; }
template<typename F_, typename T_>
constexpr auto apply(F_ f, Type<T_> t) noexcept
{
return f(t);
}
int main(void)
{
Type<int> t_i;
apply(add_pointer, t_i);
}
this produces the compiler error:
error: no matching function for call to ‘apply(< unresolved overloaded function type >, sigma::meta::Type&)’
apply(add_pointer, t_i);
any help is appreciated!
You can simply wrap your functions within functors.
As a minimal, working example:
template<typename>
struct Type {};
template<typename>
struct type_c {};
template<typename T_>
struct add_pointer {
static constexpr auto invoke(Type<T_>) noexcept
{ return type_c<T_ *>{}; }
};
template<template<typename> class F_, typename T_>
constexpr auto apply(Type<T_> t) noexcept {
return F_<T_>::invoke(t);
}
int main(void) {
Type<int> t_i;
apply<add_pointer>(t_i);
}
If you can't change them directly, create functors that forward everything to the right function through a static constexpr member method.
I am just asking about how to do "template < typename > bool Function_" as the bool part is invalid in c++ currently.
As far I know, template-template arguments are a completely different thing. They are intended for containers, not for functions. So class, not bool.
here is an example of why I can't pass the "is_pointer" to the function
Your example doesn't work because add_pointer is a template function, so when you call
apply(add_pointer, t_i);
the compiler doesn't know which version (which type T) of add_pointer to use.
A solution can be explicit it, as in the following simplified example
#include <tuple>
#include <iostream>
template <typename T>
constexpr auto add_pointer(std::tuple<T>) noexcept
{ std::cout << "add_pointer" << std::endl; return 0; }
template <typename F, typename T>
constexpr auto apply(F f, std::tuple<T> t) noexcept
{ return f(t); }
int main(void)
{
std::tuple<int> t_i { 1 };
apply<int(*)(std::tuple<int>)>(add_pointer, t_i);
}
but I understand that explicating int(*)(std::tuple<int>) is a big pain in the ass.
You can simplify a little using the fact that you pass t so you can deduce the type of the argument received by the function, but (for a generic solution) I don't know how to avoid to explicit the return type of the function (maybe it's possible, but (in this moment) I don't know.
So you can simplify the call as follows
apply<int>(add_pointer, t_i);
and the following is a little more general example
#include <tuple>
#include <iostream>
template <typename ... Ts>
constexpr auto add_pointer(std::tuple<Ts...> const &) noexcept
{ std::cout << "add_pointer" << std::endl; return 0; }
template <typename R, typename ... Ts,
typename F = R(*)(std::tuple<Ts...> const &)>
constexpr auto apply(F f, std::tuple<Ts...> t) noexcept
{ return f(t); }
int main(void)
{
std::tuple<int> t_i { 1 };
apply<int>(add_pointer, t_i);
}
I am writing a library where the user provides a callback as a lambda. In the default scenario I want to just call the lambda and pass the back an object.
Now there are non trivial senarios where the user may want the context as well. So I want to be able to use the same callback mechanism and just allow the user to add a context as a parameter to their lambda and I will then pass both the object and the context.
I can't quite get SFINAE to work.
I have simplified the code to this:
#include <string>
#include <iostream>
class Context {};
template<typename F>
struct UseContext
{
// I want to set this value to 0 or 1 based on the parameters
// in F but can't quite get this to work.
enum {value = 0 };
};
template<typename F, typename T, bool useContext = UseContext<F>::value>
struct Caller;
template<typename F, typename T>
struct Caller<F, T, true>
{
void operator()(F& func, Context& context, T& object)
{
func(context, object);
}
};
template<typename F, typename T>
struct Caller<F, T, false>
{
void operator()(F& func, Context&, T& object)
{
func(object);
}
};
template<typename T, typename F>
void doWork(F&& func)
{
Context context;
T object;
/// STUFF
Caller<F,T> caller;
caller(func, context, object);
}
Usage:
int main()
{
// if UseContext::value == 0 then this compiles.
// This is the normal situation.
doWork<std::string>([](std::string const& x){ std::cout << x << "\n";});
// if UseContext::value == 1 then this compiles.
// This is if the user wants more context about the work.
// most of the time this extra parameter is not required.
// So I don't want to force the user to add it to the parameter
// list of the lambda.
doWork<std::string>([](Context&, std::string const& x){ std::cout << x << "\n";});
}
Or if there is a better way of doing this.
Expression SFINAE:
template<class F, class T>
auto call(F& func, Context& context, T& object) -> decltype(func(context, object), void())
{
func(context, object);
}
template<class F, class T>
auto call(F& func, Context&, T& object) -> decltype(func(object), void())
{
func(object);
}
Then just call(func, context, object). This is ambiguous if both forms are valid. If you want to disambiguate, just add a dummy parameter and do the usual int/long trick.
My solution is to use std::is_constructible plus std::enable_if:
template<typename F,typename T>
typename std::enable_if<std::is_constructible<std::function<void(T const&)>,F>::value>:type doWork(F func)
{
//...
}
template<typename F,typename T>
typename std::enable_if<std::is_constructible<std::function<void(Context&,T const&)>,F>::value>:type doWork(F func)
{
//...
}
explenation - each std::function can be built from the equivilant lambda. here we are testing using std::enable_if if you can build a std::function<void(T)> or a std::function<void(Context,T)> and re-wire the correct function in compile time.
I created a template class containing a std::function as a member the following way:
template<typename Ret, typename... Args>
class Foo
{
private:
std::function<Ret(Args...)> _func;
public:
Foo(const std::function<Ret(Args...)>& func):
_func(func)
{}
};
In order not to have to specify the arguments and return type of the passed function, I created some make_foo overloads:
template<typename Ret, typename... Args>
auto make_foo(Ret (&func)(Args...))
-> Foo<Ret, Args...>
{
return { std::function<Ret(Args...)>(func) };
}
template<typename Ret, typename... Args>
auto make_foo(const std::function<Ret(Args...)>& func)
-> Foo<Ret, Args...>
{
return { func };
}
However, I was unable to create a make_foo overload that takes a lambda as parameter:
template<typename Ret, typename... Args>
auto make_foo(??? func)
-> Foo<Ret, Args...>
{
return { std::function<Ret(Args...)>(func) };
}
I just can't find a way to have the return type and argument types automatically deduced from the lambda. Is there an idiomatic way to solve such a problem?
Ok, so I thought I would die, but I finally managed to do it ç_ç
First, I used the usual indices. Since I do not have the official ones, I used old indices I wrote some months ago:
template<std::size_t...>
struct indices {};
template<std::size_t N, std::size_t... Ind>
struct make_indices:
make_indices<N-1, N-1, Ind...>
{};
template<std::size_t... Ind>
struct make_indices<0, Ind...>:
indices<Ind...>
{};
Then, I used some function traits found somewhere on StackOverflow. They are nice, and I think that they are equivalent to the Boost library linked in the comments:
template<typename T>
struct function_traits:
function_traits<decltype(&T::operator())>
{};
template<typename C, typename Ret, typename... Args>
struct function_traits<Ret(C::*)(Args...) const>
{
enum { arity = sizeof...(Args) };
using result_type = Ret;
template<std::size_t N>
using arg = typename std::tuple_element<N, std::tuple<Args...>>::type;
};
Then, I was able to write a proper make_foo function and it implementation function, since both are required to use indices. Be careful, it's plain ugly:
template<typename Function, std::size_t... Ind>
auto make_foo_(Function&& func, indices<Ind...>)
-> Foo<
typename function_traits<typename std::remove_reference<Function>::type>::result_type,
typename function_traits<typename std::remove_reference<Function>::type>::template arg<Ind>...>
{
using Ret = typename function_traits<typename std::remove_reference<Function>::type>::result_type;
return { std::function<Ret(typename function_traits<typename std::remove_reference<Function>::type>::template arg<Ind>...)>(func) };
}
template<typename Function, typename Indices=make_indices<function_traits<typename std::remove_reference<Function>::type>::arity>>
auto make_foo(Function&& func)
-> decltype(make_foo_(std::forward<Function>(func), Indices()))
{
return make_foo_(std::forward<Function>(func), Indices());
}
The code is somehow ugly and unreadable, but it definitely works. Hope it does not rely on some implementation-defined behaviour now. Also, thanks all for your advice, it helped! :)
int main()
{
auto lambda = [](int i, float b, long c)
{
return long(i*10+b+c);
};
auto foo = make_foo(lambda);
std::cout << foo(5, 5.0, 2) << std::endl; // 57, it works!
}
And here is the live example :)
I have an example that works with mutable lambdas. I can't quite figure out how to get the CV member qualification right.
First, here's the function template we're after:
#include <functional>
template <typename R, typename ...Args>
void foo(std::function<R(Args...)> f)
{ }
Now we'll let a function template bar take an arbitrary lambda and call the right version of foo, by inspecting the type of the lambda's operator():
#include <type_traits>
template <typename> struct remove_member;
template <typename C, typename T>
struct remove_member<T C::*>
{ using type = T; };
template <typename F>
void bar(F f)
{
using ft = decltype(&F::operator());
foo(std::function<typename remove_member<ft>::type>(f));
}
Example:
int q;
bar([&](int a, int b) mutable -> int { q = a + b; return q / b; });
You can use normal, const lambdas with this modified trait, though I don't like having to spell the function type out:
template <typename C, typename R, typename ...Args>
struct remove_member<R (C::*)(Args...) const>
{ using type = R(Args...); };
I thought it might work with the original code if I use typename std::remove_cv<T>::type, but at least on GCC this doesn't work because of some strange __attribute__((const)) that's set on the lambda's operator type which seems to interfere with the template specialization.
template <typename T, typename Y, typename... Args>
class Bar
{
T& t;
public:
Bar(T& t) : t(t) { }
};
template <typename T, typename... Args>
void Foo(T &function) { new Bar<T, void, Args...>(function); }
int main()
{
auto foo = [] { };
Foo(foo); // ok
Foo([] { }); // fails (tested on GCC 4.5.3)
}
Why does it only fail when the lambda expression is written inline as an argument to Foo?
template <typename T, typename... Args>
void Foo(T &function) { new Bar<T, void, Args...>(function); }
Foo([] { }); // fails (tested on GCC 4.5.3)
Lambda is temporary. Don't try bind temporary to reference. Use value, or const-reference or rvalue-reference.