Lambda callback depends on its parameters - c++

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.

Related

How can I have a function pointer template as a template parameter?

I am trying to create a class template that expects a type and a function pointer as template parameters. The function pointer is expected to be a member function of the type passed in. I want the user of the class template to be able to pass in a void member function of the type passed in. That member function will then be called on instances of the type passed in every time a certain function of the class template is called. It's a bit hard to explain but it's supposed to work sort of like this:
template<Type, Function> // For the purpose of explaining it
class Foo
{
public:
template<Args... args>
void callOnAll(Args... args)
{
for(Type* ptr : ptrs_)
{
ptr->Function(std::forward<Args>(args)...);
}
}
private:
std::vector<Type*> ptrs_;
}
Assuming that something like this is possible (which I realize it might not be), the key would have to be getting the template parameters for the class right, and getting the update function right. This is what I've come up with but I still can't get it to work:
template<typename T, template<typename... Args> void(T::*func)(Args... args)>
class EngineSystem
{
public:
template<typename... Args>
void update(Args... args)
{
for (T* handler : handlers_)
{
((*handler).*func)(std::forward<Args>(args)...);
}
}
private:
std::vector<T*> handlers_;
};
The code above does not compile. It points me to the line where I declare the template parameters for the class, underlines void and says expected 'class' or 'typename'.
Is it clear what I'm trying to achieve, and is it possible?
C++ doesn't allow non-type template template parameters. That means you can't have a parameter-pack for your member-function pointer parameter.
Assuming you're using C++17 or newer, you can use an auto template parameter instead:
template<typename T, auto func>
public:
template<typename... Args>
void update(Args... args)
{
for (T* handler : handlers_)
{
(handler->*func)(std::forward<Args>(args)...);
}
}
private:
std::vector<T*> handlers_;
};
Live Demo
Technically that will accept any object for func, but assuming update is called, then (handler->*func)(std::forward<Args>(args)...) still has to be well-formed or compilation will fail.
If you want compilation to fail even if update never gets called, you could use some type traits and a static_assert (or some SFINAE hackery, if you need it) to ensure that func is actually a pointer to a member function of T:
template <typename T, typename U>
struct IsPointerToMemberOf : std::false_type {};
template <typename T, typename U>
struct IsPointerToMemberOf<T, U T::*> : std::true_type {};
template <typename T, typename U>
struct IsPointerToMemberFunctionOf
: std::integral_constant<
bool,
IsPointerToMemberOf<T, U>::value && std::is_member_function_pointer<U>::value
>
{};
template<typename T, auto func>
class EngineSystem
{
static_assert(IsPointerToMemberFunctionOf<T, decltype(func)>::value, "func must be a pointer to a member function of T");
//...
};
Live Demo
#include <iostream>
#include <vector>
template <typename T, typename... Args>
class EngineSystem
{
public:
EngineSystem(void(T::*fun)(Args... args)): fun(fun)
{
}
void update(Args... args)
{
for (T* handler : handlers_)
{
(handler->*fun)(std::forward<Args>(args)...);
}
}
void push(T* t){
handlers_.push_back(t);
}
private:
void(T::*fun)(Args... args);
std::vector<T*> handlers_;
};
struct A {
int x = 3;
void fn(int a, int b){
std::cout << a << b << x;
}
};
template <typename T, typename... Args>
auto makeEngine(void(T::*fun)(Args... args)){
return EngineSystem<T, Args...>(fun);
}
int main() {
EngineSystem<A, int, int> as(&A::fn);
// or deduce types automatically
auto es = makeEngine(&A::fn);
A a;
es.push(&a);
es.update(1,2);
return 0;
}
https://gcc.godbolt.org/z/Pcdf9K9nz

function parameter pack for member variable pointer

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.

Handling a void variable in a templatized function in C++11

I have a template class that must perform some operation before calling a function whose parameters and return type are generic.
This is the method:
template <typename ReturnType, typename ...Args>
ReturnType function (Args ...args) {
// prepare for call
// ...
ReturnType rv = makeCall(args...); // [1]
// dismiss the call
// ...
return rv;
}
Of course it's compiling correctly when ReturnType is not void.
When I use it in this context:
function<void>(firstArg, secondArg);
The compiler responds with
error: return-statement with a value, in function returning 'void' [-fpermissive]
pointing to the line marked with [1].
Is there any solution other than passing -fpermissive to the compiler?
I would prefer to have a unique method, because I possible solution I found is to instantiate different versions using enable_if and is_same.
Thank you in advance.
-- Update --
This is a complete example. I should have said that our functions are indeed class methods.
#include <type_traits>
#include <iostream>
class Caller {
public:
Caller() {}
template <typename ReturnType, typename ...Arguments>
ReturnType call(Arguments ... args) {
prepare();
ReturnType rv = callImpl<ReturnType>(args...);
done();
return rv;
}
private:
void prepare() {
std::cout << "Prepare\n";
}
void done() {
std::cout << "Done\n";
}
template <typename ReturnType, typename ...Arguments>
typename std::enable_if<std::is_same<ReturnType, void>::value, ReturnType>::type callImpl ( Arguments ... args) {
std::cout << "Calling with void\n";
return;
}
template <typename ReturnType, typename ...Arguments>
typename std::enable_if<std::is_same<ReturnType, bool>::value, ReturnType>::type callImpl (Arguments ... args) {
std::cout << "Calling with bool\n";
return true;
}
template <typename ReturnType, typename ...Arguments>
typename std::enable_if<std::is_same<ReturnType, int>::value, ReturnType>::type callImpl (Arguments ... args) {
std::cout << "Calling with int\n";
return 42;
}
};
int main(int argc, char *argv[]) {
Caller c;
auto rbool = c.call<bool> (1,20);
std::cout << "Return: " << rbool << "\n";
auto rint = c.call<int> (1,20);
std::cout << "Return: " << rint << "\n";
// the next line fails compilation. compile with --std=c++11
c.call<void>("abababa");
return 0;
}
-- Update --
Not a big issue: Use std::bind(&Caller::callImpl<ReturnType>, this, args).
Here's my attempt at a general C++11-compliant solution that you can easily reuse.
Let's start by creating a simple type trait that converts void to an empty struct. This doesn't introduce any code repetition.
struct nothing { };
template <typename T>
struct void_to_nothing
{
using type = T;
};
template <>
struct void_to_nothing<void>
{
using type = nothing;
};
template <typename T>
using void_to_nothing_t = typename void_to_nothing<T>::type;
We also need a way to call an arbitrary function converting an eventual void return type to nothing:
template <typename TReturn>
struct helper
{
template <typename TF, typename... Ts>
TReturn operator()(TF&& f, Ts&&... xs) const
{
return std::forward<TF>(f)(std::forward<Ts>(xs)...);
}
};
template <>
struct helper<void>
{
template <typename TF, typename... Ts>
nothing operator()(TF&& f, Ts&&... xs) const
{
std::forward<TF>(f)(std::forward<Ts>(xs)...);
return nothing{};
}
};
template <typename TF, typename... Ts>
auto with_void_to_nothing(TF&& f, Ts&&... xs)
-> void_to_nothing_t<
decltype(std::forward<TF>(f)(std::forward<Ts>(xs)...))>
{
using return_type =
decltype(std::forward<TF>(f)(std::forward<Ts>(xs)...));
return helper<return_type>{}(std::forward<TF>(f), std::forward<Ts>(xs)...);
}
Usage:
template <typename ReturnType, typename ...Args>
void_to_nothing_t<ReturnType> function (Args ...args) {
// prepare for call
// ...
auto rv = with_void_to_nothing(makeCall, args...); // [1]
// dismiss the call
// ...
return rv;
}
live wandbox example
There's a proposal by Matt Calabrese called "Regular Void" that would solve this issue. You can find it here: "P0146R1".
Depending on what you wish to accomplish in the lines
// dismiss the call
you might be able to use:
template <typename ReturnType, typename ...Args>
ReturnType function (Args ...args) {
// prepare for call
// ...
CallDismisser c;
return makeCall(args...); // [1]
}
That would work as long as the destructor of CallDismisser can do everything you need to do.
struct nothing {};
template<class Sig>
using returns_void = std::is_same< std::result_of_t<Sig>, void >;
template<class Sig>
using enable_void_wrap = std::enable_if_t< returns_void<Sig>{}, nothing >;
template<class Sig>
using disable_void_wrap = std::enable_if_t< !returns_void<Sig>{}, std::result_of_t<Sig> >;
template<class F>
auto wrapped_invoker( F&& f ) {
return overload(
[&](auto&&...args)->enable_void_wrap<F(decltype(args)...)> {
std::forward<F>(f)(decltype(args)(args)...);
return {};
},
[&](auto&&...args)->disable_void_wrap<F(decltype(args)...)> {
return std::forward<F>(f)(decltype(args)(args)...);
}
);
}
so wrapped_invoker takes a function object, and makes it return nothing instead of void.
Next, holder:
template<class T>
struct holder {
T t;
T&& get()&& { return std::forward<T>(t); }
};
template<>
struct holder<void> {
template<class T>
holder(T&&) {} // discard
void get()&& {}
};
holder lets you hold the return value and convert back to void if needed. You must create holder<T> using {} to get reference lifetime extension to work properly. Adding a ctor to holder<T> will break it.
holder<void> silently discards anything passed to it.
template <typename ReturnType, typename ...Args>
ReturnType function (Args ...args) {
// prepare for call
// ...
holder<ReturnType> rv{ wrapped_invoker(makeCall)(args...) };
// dismiss the call
// ...
return std::move(rv).get();
}
Now, holder<ReturnType> holds either nothing or the return value of makeCall(args...).
If it holds nothing, rv.get() returns void, and it is legal to return void to a function where ReturnValue is void.
Basically we are doing two tricks. First, we are preventing makeCall from returning void, and second if we are returning void we are discarding the return value of makeCall conditionally.
overload isn't written here, but it is a function that takes 1 or more function objects (such as lambdas) and returns their overload set. There is a proposal for std::overload, and a myriad of examples on stackoverflow itself.
Here is some:
Overloaded lambdas in C++ and differences between clang and gcc
C++11 “overloaded lambda” with variadic template and variable capture
The problem seems to be with //Dismiss the call.
This code shouldn't exist. That's what we have RAII for. The following code does work, even with ReturnType = void.
template <typename ReturnType, typename ...Arguments>
ReturnType call(Arguments ... args) {
Context cx;
return callImpl<ReturnType>(args...);
}
Context::Context() { std::cout << "prepare\n"; }
Context::~Context() { std::cout << "done\n"; }

Is it possible to place function pointer in template parameter ahead of dependent type?

I have a template that has a function pointer as it's 2nd parameter and a type that the function pointer is dependent on as it's first.
i.e.
template <typename P, typename void(*fn)(P)>
auto function(P) -> otherType<P, fn>;
I want to make it so that I can just specify the function pointer in the template list without having to specify the dependent type as that type should somehow be able to be inferred from the function pointer that I specify (or maybe even the parameter list, but I think that it probably is too far down the line).
My first thought was to defer the conversion to a template parameter value, by passing a template typename and then convert to a value after the fact though template metaprogramming wizardry.
i.e.
template <typename F, typename P>
auto function(P) -> [[ something here to get otherType<P, fn> if F was a function pointer ]]
However, I'm not sure how I can do this. Any ideas?
Edit
What I'm trying to accomplish here is to make a helper function that will generate a class object. So, given what was said by StenSoft, this is what I've come up with. Unfortunately it doesn't work with a failure inside the main() function where it cannot match to the correct function due to deduction failure:
#include <iostream>
#include <functional>
template<typename T, typename F>
struct wrapper_fntor
{
T m_t;
F m_f;
wrapper_fntor(T t, F f) : m_t(t), m_f(f) {}
void invoke() { m_f(m_t); }
};
template<typename T, void(*fn)(T)>
struct wrapper_fn
{
T m_t;
wrapper_fn(T t) : m_t(t) {}
void invoke() { fn(m_t); }
};
template <typename T>
struct Wrapper;
template <typename Ret, typename P>
struct Wrapper<Ret(P)>
{
template <Ret(*fn)(P)>
static Ret function(P p)
{
return fn(std::forward<P>(p));
}
template <Ret(*fn)(P)>
static P get_param_type(P);
typedef decltype(get_param_type<Ret(P)>()) param_t;
};
template<typename F>
wrapper_fn<typename Wrapper<F>::param_t, &Wrapper<F>::function> make_wrapper(typename Wrapper<F>::param_t param)
{
return wrapper_fn<typename Wrapper<F>::param_t, &Wrapper<F>::function>(param);
}
template<typename F>
wrapper_fntor<typename Wrapper<F>::param_t, F> make_wrapper(typename Wrapper<F>::param_t param, F fntor)
{
return wrapper_fntor<typename Wrapper<F>::param_t, F>(param, fntor);
}
void function(int value)
{
std::cout << "function called " << value << std::endl;
}
int main()
{
auto x = make_wrapper<function>(3);
x.invoke();
}
demo
For a similar problem I have used a templated function inside a templated wrapper class and a macro (this actually works with any parameters and return type):
template <typename T>
struct Wrapper;
template <typename Ret, typename... Params>
struct Wrapper<Ret(Params...)>
{
template <Ret(*fn)(Params...)>
static Ret function(Params... params)
{
return fn(std::forward<Params>(params)...);
}
};
#define FUNCTION(fn) \
Wrapper<decltype(fn)>::function<fn>

Passing template function pointer to template as template parameter is too verbose

template<class T, class... TA> Uptr<T, TA> makeUniquePtr(/*...*/) { /*...*/ };
template<class T, class... TA> Sptr<T, TA> makeSharedPtr(/*...*/) { /*...*/ };
template<typename TFPType, TFPType TFP> void func(/*...*/) { /*...*/ }
template<class T, class... TA> void implementation1(/*...*/)
{
// Can this be reduced to func<&makeUniquePtr, T, TA...>?
func<decltype(&makeUniquePtr<T, TA...>), &makeUniquePtr<T, TA...>>(/*...*/);
}
template<class T, class... TA> void implementation2(/*...*/)
{
// Can this be reduced to func<&makeSharedPtr, T, TA...>?
func<decltype(&makeSharedPtr<T, TA...>), &makeSharedPtr<T, TA...>>(/*...*/);
}
Calling func</*...*/>(/*...*/) is extremely verbose. Is there a way to simply call
func<&makeSharedPtr, T, TA...>(/*...*/)
and internally use
&makeSharedPtr<T, TA...>
without having the user specify it twice?
Create a shared maker stateless function object class, like std::less, but with no template parameters itself: instead operator() perfect forwards to your template function.
Pass it instead of your function pointer.
If you need template arguments passed to it, either create a static method to it, or make the entire template class take the arguments and use them in the operator().
Here is an example of late-bound template arguments (live example):
#include <iostream>
// test stubs:
template<typename... Ts>
using UPtr = int;
template<typename... Ts>
using SPtr = double;
template<typename T, typename...TA>
UPtr<T,TA...> makeUniquePtr() {
std::cout << "makeUniquePtr\n";
return {};
}
template<typename T, typename...TA>
SPtr<T,TA...> makeSharedPtr() {
std::cout << "makeSharedPtr\n";
return {};
}
// perfect forwarding make static functions passed by class name:
struct unique_ptr_maker {
template<typename T, typename...TA, typename...Args>
static UPtr<T, TA...> make(Args&&...args) {
return makeUniquePtr<T, TA...>( std::forward<Args>(args)... );
}
};
struct shared_ptr_maker {
template<typename T, typename...TA, typename...Args>
static SPtr<T, TA...> make(Args&&...args) {
return makeSharedPtr<T, TA...>( std::forward<Args>(args)... );
}
};
// your `func`. It can take args or whatever:
template<typename maker, class T, class... TA> void func() {
std::cout << "func\n";
maker::template make<T, TA...>();
}
// a sample of implementation 1 and 2:
template<class T, class... TA> void implementation1()
{
func<unique_ptr_maker, T, TA...>();
}
template<class T, class... TA> void implementation2()
{
func<shared_ptr_maker, T, TA...>();
}
// and, to test, always instantiate:
int main() {
implementation1<int, double>();
implementation2<int, char>();
return 0;
}
with much of the functionality stubbed out, as you did not detail what it was supposed to do in your question.
Making a few assumptions on intended use from your names, I would try something like this:
template<class T>
struct makeUniquePtr {
template<class... TA>
Uptr<T, TA> operator()(TA&&...) const { /*...*/ }
};
template<class T>
struct makeSharedPtr {
template<class... TA>
Sptr<T, TA> operator()(TA&&...) const { /*...*/ }
};
template<class F> void func(/*...*/) { /*...*/ }
template<class T, class... TA> void implementation1(/*...*/)
{
func<makeUniquePtr<T>>(/*...*/);
}
template<class T, class... TA> void implementation2(/*...*/)
{
func<makeSharedPtr<T>>(/*...*/);
}
Unlike Yakk's solution, here parameters TA... are automatically deduced, as is the case for std::make_unique etc.
EDIT My reference to Yakk's solution was made before that solution was edited. I now see it is expanded.