Trying to pass a lambda function to a template factory function which is templated on the function arguments of the passed function leads gcc-10.2.0 to report no matching function for call to ‘test(main()::<lambda(int, double)>)’.
It does seem to work when I add a + in front of the lambda function forcing the conversion to a function pointer, but I don't see why that would be necessary. Why does the conversion not happen automatically? Is there any way to make this work?
I have also tried std::function<void(TArgs...)> test_func as argument in the declaration of make_test, however that gives me the same no matching function for call error.
#include <iostream>
template <typename... TArgs>
struct test_type {
test_type(void(TArgs...)) {};
};
template <typename... TArgs>
test_type<TArgs...> make_test(void test_func(TArgs...)) {
return test_type<TArgs...>{test_func};
}
int main() {
auto test_object = make_test([](int a, double b) { std::cout << a << b << "\n"; });
return 0;
}
Edit
I was wondering if there maybe is some way to make it work with type traits. Something like the following. Although I know of no way to get the argument list from the template parameter.
template <typename F>
test_type<get_arg_list<F>> make_test(std::function<F>&& f) {
return test_type<get_arg_list<F>>{std::forward(f)};
}
In order to support a variety of callables being passed to your factory (e.g., a stateful lambda or a function pointer), your test_type constructor should accept some kind of type-erased function type like std::function<void(int, double)>:
template<class... TArgs>
struct test_type {
test_type(std::function<void(TArgs...)>) {};
};
Afterwards it's just a matter of writing the boilerplate to handle the following callables being passed to make_test
a regular function pointer
a lambda (struct with a operator()(...) const)
a mutable lambda or a user defined callable without a const operator() function
Here is one approach using type traits:
Start with a base class that we'll specialize for each scenario:
template<class T, class = void>
struct infer_test_type;
(This is a common setup for the voider pattern. We can do this with concepts and constraints, but I'm feeling too lazy to look up the syntax, maybe later)
Regular function pointer specialization
template<class Ret, class... Args>
struct infer_test_type<Ret(*)(Args...)>
{
using type = test_type<Args...>;
};
Now we can write a templated alias for simplicity:
template<class T>
using infer_test_type_t = typename infer_test_type<T>::type;
And we can verify that it works like so:
void foo(int, double){}
// ...
static_assert(std::is_same_v<infer_test_type_t<decltype(&foo)>, test_type<int, double>>);
We can use the type trait for our make_test function like so:
template<class T>
auto make_test(T&& callable) -> infer_test_type_t<T>
{
return infer_test_type_t<T>{std::forward<T>(callable)};
}
Now it's just a matter of covering our other two scenarios.
Callable objects
these will have operator() (either const or not)
I'll start with a top level trait to detect the presence of operator() and feed the type of operator() into another trait.
The top level trait:
// if T is a callable object
template<class T>
struct infer_test_type<T, std::void_t<decltype(&T::operator())>>
{
using type = typename infer_test_type<decltype(&T::operator())>::type;
};
You see that internally it's calling back into another infer_test_type specialization that I haven't shown yet; one that is specialized for operator(). I'll show the two specializations now:
// if operator() is a const member function
template<class T, class Ret, class... Args>
struct infer_test_type<Ret(T::*)(Args...) const>
{
using type = test_type<Args...>;
};
// if operator() is non-const member function
template<class T, class Ret, class... Args>
struct infer_test_type<Ret(T::*)(Args...)>
{
using type = test_type<Args...>;
};
(We could probably combine these two if we wanted to be a little bit smarter and lop off any const at the high level before calling down, but I think this is more clear)
And now we should be able to infer an appropriate test_type for non-generic callables (no generic lambdas or templated operator() functions):
a test with a non-const operator():
struct my_callable
{
void operator()(int, double) // non-const
{
}
};
// ...
static_assert(std::is_same_v<infer_test_type_t<my_callable>, test_type<int, double>>);
And a test with your lambda:
auto lambda = [](int a, double b) { std::cout << a << b << "\n"; };
static_assert(std::is_same_v<infer_test_type_t<decltype(lambda)>, test_type<int, double>>);
Putting it all together
For your simple (non-capturing, non-generic lambda) example it's quite straightforward:
make_test([](int a, double b) { std::cout << a << b << "\n"; });
Demo
Related
We implement a system that passes callbacks to object-instance member-functions. This works nicely, see the code below. The problem is that the current state of the implementation handles only non-const member functions.
The code below compiles and demonstrates that the system is working. As soon as the /* const */ is included, it no longer compiles.
The error messages are localized not English, but the first message is 'incomplete type'.
Logically, a call to a const member-function should be not more constrained than a call to a non-const member-function, so it seems that the basic goal is sensible.
It is clear that the type of a const-member differs from that of a non-const member. The problem is that we do not find a way to express to the compiler that the code is also valid for const members.
Where and how in the shown WrapP can we express that a const is acceptable? Is it possible to define a single template that accepts both, const and non-const, member functions?
#include <algorithm>
#include <functional>
#include <iostream>
using std::cout;
using std::endl;
template <auto F>
struct WrapP;
template <typename T, typename R, typename ... Args, R(T::* F)(Args...)>
struct WrapP<F> {
T* obj_;
WrapP(T* instance) : obj_(instance) {}
auto operator()(Args... args) const {
return (obj_->*F)(args...);
}
};
struct foo {
// Const below is needed, but could not be activated.
auto bar(double) /* const */ -> int {
return 314; };
};
int main() {
foo x;
// Create a functor for foo::bar
WrapP<&foo::bar> fp{ &x };
// Call the functor.
std::cout << fp( 3.14159265 ) << std::endl;
return 0;
}
If you want to specialize WrapP for a const member function, you need to specify that:
template <typename T, typename R, typename ... Args, R(T::* F)(Args...) const>
struct WrapP<F> { // ^___^
// ...
};
As far as I'm aware, there isn't a way to allow for either const or non-const member function pointers in a template parameter list, so you'll have to write separate specializations for those cases.
Do not specialize WrapP -- instead keep taking auto F as your template parameter, and then extract the information you need using something like Boost.CallableTraits or your own homegrown solution:
template <auto F>
struct WrapP {
using T = boost::callable_traits::class_of_t<decltype(F)>;
using R = boost::callable_traits::return_type_t<decltype(F)>;
T* obj_;
WrapP(T* instance) : obj_(instance) {}
template <typename... Args>
auto operator()(Args... args) const {
return (obj_->*F)(args...);
}
};
It is also possible to extract Args... but it's a bit more cumbersome as you get a std::tuple back.
I want to create a generator which for each pointer to function will create a static function to which the pointer can point to:
template <auto &PtrToIsrHandler, auto MemberFunction> struct enable_member_isr_handler
{
using TypeOfCFunPtr = std::remove_reference_t<decltype(PtrToIsrHandler)>;
using TypeOfCFunPointed = std::remove_pointer_t<TypeOfCFunPtr>;
using RetType = std::invoke_result_t<TypeOfCFunPointed>;
static RetType isr_handler(/* dunno what to put here */)
{
return /* call MemberFunction here somehow */;
}
enable_member_isr_handler()
{
PtrToIsrHandler = isr_handler;
}
};
In the parameter list of the isr_handler method I tried to put a tuple by using:
template <typename T> struct get_parameters;
template <typename Ret, typename... Args> struct get_parameters<Ret(Args...)>
{
using args_t = std::tuple<Args...>;
};
But I get then:
error: invalid conversion from void (*)(get_parameters<void()>)}’ to ‘void (*)()’
How can I make it in such a way that PtrToIsrHandler could be a valid pointer to isr_handler?
As mentioned in my comment, one approach to get the argument list is to use partial specialization and forward the type of the passed in member function. The same approach can be used on free functions as well.
#include <iostream>
template <auto MemberFunction, class MemberFunctionType>
struct handler_impl;
template <auto MemberFunction, class ReturnType, class ClassType, class... Args>
struct handler_impl<MemberFunction, ReturnType(ClassType::*)(Args...)> {
// here you have access to return-type, class-type and args
static ReturnType call_on_instance(ClassType& obj, Args... args) {
return (obj.*MemberFunction)(args...);
}
};
template <auto MemberFunction>
using handler = handler_impl<MemberFunction, decltype(MemberFunction)>;
struct Foo {
int print(int x) {
std::cout << x*x << std::endl;
return x;
}
};
int main() {
Foo f;
handler<&Foo::print>::call_on_instance(f, 7);
}
One thing to keep in mind here is that we are not using perfect forwarding. The easiest approach is to simply make call_on_instance a template function, then we don't really need to care about the arguments and return value, we can let the compiler deduce it.
Another option is to use the approach I showed above and use a static_assert to make sure the argument list passed in is valid, and thus give a better error message when used in the wrong way.
I'm creating a generic C++ EventEmitter. It's based on Node.js EventEmitter:
template <typename ...Args>
int16_t EventEmitter::addListener(uint32_t eventId, std::function<void(Args...)> cb)
{
...
}
template <typename... Args>
void EventEmitter::emit(uint32_t eventId, Args... args)
{
...
}
It's working as expected (I can register listeners with different prototypes). Eg.:
auto handler = [](int n) { ... };
listener.addListener(0, std::function<void(int)>(handler));
But I don't want to bother typing the whole listener prototype to std::function<...> every time I add one (some have more than 5 parameters), then I decided to create a macro:
#define STDFUNC(fn) std::function<decltype(fn)>(fn)
The problem is when I try to use it with lambdas: decltype(handler) is not void(int), it's class lambda []void (int n)->void instead, generating the error:
(Clang 3.7.1) -> error : implicit instantiation of undefined template
'std::_Get_function_impl<(lambda at ...
I'm scratching my head to get the prototype without that lambda qualifiers but I'm stuck. Any help will be appreciated.
Here is a small program that generates a function object for an arbitrary lambda:
#include <functional>
#include <type_traits>
template <typename R, typename... A>
class build_func_type
{
public:
using type = ::std::function<R(A...)>;
};
template <typename R, typename C, typename... A>
typename build_func_type<R, A...>::type mem_func_to_func( R(C::*)(A...) const)
{
return nullptr;
}
template <typename T>
decltype(mem_func_to_func(&T::operator ())) lambda_to_fp(T le)
{
using func_t = decltype(mem_func_to_func(&T::operator ()));
return func_t{le};
}
int test()
{
auto foo = [](int x) -> int { return x * x; };
auto ftype = lambda_to_fp(foo);
return ftype(5);
}
It uses the function mem_func_to_func to auto-deduce the type of the lambda's operator (). It then uses the build_func_type template to build a function type out of the components of the type of the lambda's operator (). I could possibly have used a constructor in build_func_type and relied on C++17 constructor type deduction for this.
Then lambda_to_fp will take a lambda, using mem_func_to_func to create a pointer to the appropriate function type from a pointer to the lambda's operator () member function. Then it creates a ::std::function of the appropriate type, constructing that type from the type of the function pointer. Then it initializes it with the lambda and returns it.
I have a member function with a variable number of parameters, stored in a std::function, and I want to bind the instance and get an independent function object.
template <class T, class R, class... Args>
void connect(const T& t, std::function<R(const T&, Args...)> f) {
std::function<R(Args...)> = /* bind the instance c into the function? */
}
// ...
Class c;
connect(c, &Class::foo);
For a fixed number of arguments I'd use std::bind, but I don't see how to do this for variadic parameters.
I hope this is what you were trying to achieve:
#include <iostream>
#include <cstdarg>
#include <functional>
class Class {
public:
void foo(...)
{
std::cout << "foo" << std::endl;
}
};
template <typename RES_T>
using ClassVarMemFunT = RES_T (Class::*)(...);
// Without typedef:
// template <class... ARGS, class CLASS_T, class RES_T>
// std::function<RES_T(ARGS...)> connect(CLASS_T& object, RES_T (CLASS_T::*funPtr)(...))
template <typename... ARGS, typename CLASS_T, typename RES_T>
std::function<RES_T(ARGS...)> connect(CLASS_T& object, ClassVarMemFunT<RES_T> funPtr)
{
std::function<RES_T(ARGS...)> resultFun = [&object, funPtr](ARGS&&... args) -> RES_T {
return (object.*funPtr)(std::forward<ARGS>(args)...);
};
return resultFun;
}
int main() {
Class c;
auto funPtr1 = connect<int, float>(c, &Class::foo);
funPtr1(10, 2.f);
auto funPtr2 = connect<double, float, int>(c, &Class::foo);
funPtr2(2., 2.f, 10);
return 0;
}
In my implementation connect expects the actual argument types as template parameters. The connect function returns an std::function that expects arguments with ARGS... types.
connect has two parameters:
one for the object that has a variadic function (object).
one for the member function pointer that points to the variadic function we would like to call (funPtr).
We cannot use std::bind in the implementation (we could, but it would involve a lot of boilerplate to add as many std::placeholders as we need based on the ARGS).
So I introduce a lambda instead, that expects the actual ARGS typed arguments. We can return the lambda as an std::function and we are good to go.
https://godbolt.org/z/7cx3rcYh8
I created a version that can print out the variadic list as well:
https://godbolt.org/z/nMxj7Wh9j
I'm writing a generalized function wrapper, that can wrap any function into a lua-style call, which has the form
int lua_function( lua_State *L)
And I wish the wrapper function is generated on-the-fly, so I'm thinking of passing the function as a template argument. This is trivial if you know the number (e.g, 2) of arguments:
template <typename R, typename Arg1, typename Arg2, R F(Arg1, Args)>
struct wrapper
However, I don't know the number, so I beg for variadic template argument for help
// This won't work
template <typename R, typename... Args, R F(Args...)>
struct wrapper
The above won't compile, since variadic argument has to be the last one. So I use two level template, the outer template captures types, the inner template captures the function:
template <typename R, typename... Args>
struct func_type<R(Args...)>
{
// Inner function wrapper take the function pointer as a template argument
template <R F(Args...)>
struct func
{
static int call( lua_State *L )
{
// extract arguments from L
F(/*arguments*/);
return 1;
}
};
};
That works, except that to wrap a function like
double sin(double d) {}
the user has to write
func_type<decltype(sin)>::func<sin>::apply
which is tedious.
The question is: is there any better, user-friendlier way to do it? (I can't use a function template to wrap the whole thing, coz a function parameter can't be used as a template argument.)
Things like std::function and std::result_of use the following technique to do what you want regarding variadic templates:
template<typename Signature>
struct wrapper; // no base template
template<typename Ret, typename... Args>
struct wrapper<Ret(Args...)> {
// instantiated for any function type
};
You could expand the above to add a non-type Ret(&P)(Args...) template parameter (pointers to function work just as well) but you'd still need a decltype at the user level, i.e. wrapper<decltype(sin), sin>::apply. Arguably it would be a legitimate use of the preprocessor if you decide to use a macro to remove the repetition.
template<typename Sig, Sig& S>
struct wrapper;
template<typename Ret, typename... Args, Ret(&P)(Args...)>
struct wrapper<Ret(Args...), P> {
int
static apply(lua_State*)
{
// pop arguments
// Ret result = P(args...);
// push result & return
return 1;
}
};
// &wrapper<decltype(sin), sin>::apply is your Lua-style wrapper function.
The above compiles with gcc-4.5 at ideone.
Good luck with implementing the apply that (variadically) pops the arguments (leave me a comment if you open a question about that). Have you considered using Luabind?
As #Juraj says in his comment, the function pointer can be a template argument, see the following simple example:
#include <iostream>
#include <boost/typeof/typeof.hpp>
void f(int b, double c, std::string const& g)
{
std::cout << "f(): " << g << std::endl;
}
template <typename F, F* addr>
struct wrapper
{
void operator()()
{
std::string bar("bar");
(*addr)(1, 10., bar);
}
};
int main(void)
{
wrapper<BOOST_TYPEOF(f), &f> w;
w();
return 0;
}
working version: http://www.ideone.com/LP0TO
I'm using BOOST_TYPEOF as normally I always provide examples in the current standard, but it does something similar to decltype. Is this what you were after?