I'm trying to use a template class with a lambda function parameter. However, I don't understand how to pass the parameter. Here's what I've tried so far:
#include <iostream>
using namespace std;
template <class F>
class A {
public:
int f(int i)
{
return F(i); //*
}
};
int main(int argc, const char * argv[]) {
auto f = [](int i){return i+5;};
A<decltype(f)> a;
cout << a.f(5);
return 0;
}
I get an error in the marked line.
Can someone help?
Your example doesn't work because F is a type, not a callable object. The next step is to instantiate it by creating a member variable.
template <class F>
class A {
F function;
public:
int f(int i) {
return function(i);
}
};
However, that still won't work because lambda default constructors are deleted. That means we need another way to construct function. That can be achieved by passing an argument to A's constructor.
template<typename F>
class A {
F function;
public:
A(const F& f) : function(f) {}
int f(int i) {
return function(i);
}
};
// ...
auto f = [](int i) { return i+5; };
A<decltype(f)> a(f);
This uses the lambda copy constructor, which isn't deleted.
Live example
If you want it to work with any lambda, you can add some more magic.
template<typename F>
class A {
F function;
public:
A(const F& f) : function(f) {}
template<typename ...Args>
auto f(Args... args) -> std::result_of_t<F(Args...)> {
return function(std::forward<Args>(args)...);
}
};
Live example
If you really want to use template in order to accept any kind of function's signature, then the implementation should be something similar to this:
class A {
public:
template<typename F, typename... Args>
auto f(F&& funct, Args&&... args) {
return funct(std::forward<Args...>(args)...);
}
};
That because you've said in the comment:
Q: Does the type F is needed in the class of only for method f?
A: only the method.
Because of that, it should be useless to have a template class, when you can just have a template method.
An here, an example how to call the method which just invoke the "callable object with its parameters", in this case a lambda function:
int main(int argc, char* argv[]) {
A a;
a.f([](int i) -> int { return i + 5; }, 12);
// |------callable object-----------| |argument of function|
return 0;
}
Practically, the method f accepts as first argument a "callable object" and as further arguments any parameters requested in order to invoke the first argument.
Additional Notes:
If you want to pass to method f a certain type of signature of function, for example: int (*)(int), then you can avoid using template and pass an object of type std::function.
This is just an example:
#include <functional>
class A {
public:
// method g accept a function which get a integer and return an integer as well.
int g(std::function<int(int)> funct, int arg) {
return funct(arg);
}
};
It's not enough to define A as inherited from or somehow containing a lambda function, you still have to initialize the subobject when you create an instance of A.
To do that, as an example, you can inherit from the lambda and use A as a callable object.
It follows a minimal, working example:
#include <iostream>
using namespace std;
template <class F>
class A: public F {
public:
A(F f): F(f) {}
};
int main() {
auto f = [](int i){return i+5;};
A<decltype(f)> a{f};
cout << a(5);
return 0;
}
You don't have to define any function f to execute the lambda.
Anyway, if you want to have a function f to be called as a.f(5), you can define it as it follows:
int f(int i) {
return F::operator()(i);
}
Or as it follows:
int f(int i) {
return (*this)(i);
}
Related
I have a function wrapper for use over the network:
#pragma once
#include <tuple>
#include <functional>
struct ZPackage {
std::unique_ptr<int> m_dummy;
template<typename T>
T Read() {
T t = T();
return t;
}
};
class ZRpc;
template <class C, class Tuple, class F, size_t... Is>
constexpr auto invoke_tuple_impl(F f, C& c, ZRpc* rpc, Tuple t, std::index_sequence<Is...>) {
return std::invoke(f, c, rpc, std::move(std::get<Is>(t))...);
}
template <class C, class Tuple, class F>
constexpr void invoke_tuple(F f, C& c, ZRpc* rpc, Tuple t) {
invoke_tuple_impl(f, c, rpc, std::move(t),
std::make_index_sequence < std::tuple_size<Tuple>{} > {}); // last arg is for template only
}
class ZRpcMethodBase
{
public:
virtual void Invoke(ZRpc* pao, ZPackage& pkg) = 0;
};
template<class C, class...Args>
class ZRpcMethod final : public ZRpcMethodBase {
using Lambda = void(C::*)(ZRpc*, Args...);
C* object;
Lambda lambda;
template<class F>
auto Invoke_impl(ZPackage& pkg) {
return std::tuple(pkg.Read<F>());
}
// Split a param,
// Add that param from Packet into tuple
template<class F, class S, class...R>
auto Invoke_impl(ZPackage& pkg) {
auto a(Invoke_impl(pkg));
std::tuple<S, R...> b = Invoke_impl<S, R...>(pkg);
return std::tuple_cat(a, b);
}
public:
ZRpcMethod(C* object, Lambda lam) : object(object), lambda(lam) {}
void Invoke(ZRpc* rpc, ZPackage& pkg) override {
// Invoke_impl returns a tuple of types by recursion
if constexpr (sizeof...(Args))
{
auto tupl = Invoke_impl<Args...>(pkg);
invoke_tuple(lambda, object, rpc, tupl);
}
else
{
// works like ~magic~
std::invoke(lambda, object, rpc);
}
}
};
I have added in some of the types that are utilized, ZRpc, ZPackage, and an example Object.
I am struggling with getting this wrapper to work with types that have a deleted copy constructor, such as std::unique_ptr (or in this example the ZPackage which contains the std::unique_ptr. The specific error I get:
std::tuple::tuple(const std::tuple &)': attempting to reference a deleted function
#include "TestRpc.h"
class ZRpc { };
struct Object {
void ok_method(ZRpc* rpc, int i) {
}
void broken_method(ZRpc* rpc, ZPackage pkg) {
}
};
int main() {
ZRpc rpc;
Object obj;
// compiles fine
auto a = new ZRpcMethod(&obj, &Object::ok_method);
// does not compile
auto b = new ZRpcMethod(&obj, &Object::broken_method);
}
I doubt that it will make a difference, but just for reference, here are some things I have tried and commented out previously with no avail: https://pastebin.com/aHSsLzWe. I am unable to wrap my head around variadic templates and how to correctly forward.
How can I achieve perfect forwarding with move-only constructor types?
EDIT:
I changed the std::forward to move
In the Invoke() function body, since if constexpr (sizeof...(Args)) == 1 is true, this will invoke Invoke_impl<Args...>(pkg) which will return a std::tuple<ZPackage> which is move-only, so you also need to std::move it into invoke_tuple().
if constexpr (sizeof...(Args)) {
auto tupl = Invoke_impl<Args...>(pkg);
invoke_tuple(lambda, object, rpc, std::move(tupl));
} else {
// ...
}
Suppose that a class has a member function which should accept either a double(double) function or a class instance with a "MyStructFunc" public member function as an argument:
#include<functional>
#include <type_traits>
struct Caller
{
// (1.)
double call(std::function<double(double)> func) { return func(1); }
// (2.)
template<typename T>
double call(const T& S) { return S.MyStructFunc(2); }
};
So, for example, we can pass
double myFunc(double x) { return x * x * x; }
or
struct myStruct
{
double MyStructFunc(double x) const { return x * x; }
};
like this:
int main()
{
Caller c;
myStruct ms;
c.call(myFunc);
c.call(ms);
}
Unfortunately, I get an error. Could you please help me make it work? Thank you for your help!
function pointer is not a std::function, so your template method is a better match.
You might use SFINAE to restrict your template method:
// (2.)
template<typename T>
auto call(const T& S) -> decltype(S.MyStructFunc(2)) { return S.MyStructFunc(2); }
Demo
I want to create a wrapper class which is able to call member functions (of any type) of the wrapped class with help of templates. This is what I have so far:
template <typename T>
class wrapper {
public:
template<typename R, R (T::*func)()>
void call_func() {
(wrapped.*func)();
}
private:
T wrapped;
};
class some_class {
private:
int i = 2;
public:
void some_func() {
std::cout << i << std::endl;
}
};
int main() {
wrapper<some_class> wr;
// How I need to call at the moment:
wr.call_func<void, &some_class::some_func>();
// How I want call:
wr.call_func<&some_class::some_func>();
return 0;
}
As you can see in the comments of the main function, I want to call the wrapper-function without explicitly specifying the return type of the wrapped member function. (How) Can this be done in C++11?
template<typename F>
void call_func(F func) {
(wrapped.*func)();
}
then call like this:
wr.call_func(&some_class::some_func);
If you want to use the return value too, you'll need this:
template<typename F>
auto call_func(F func) -> decltype((std::declval<T>().*func)()) {
return (wrapped.*func)();
}
If you have C++14, you can omit the -> decltype(...) part and use decltype(auto) as the return value.
If you also want to pass functions, you can use variadic templates and forwarding for that.
template<typename F, typename... Args>
decltype(auto) call_func(F func, Args&&... args) {
return (wrapped.*func)(std::forward<Args>(args)...);
}
You can directly use std::function
For more information on std::function see: http://en.cppreference.com/w/cpp/utility/functional/function
How has the functor below to be altered to work as a lambda wrapper?
template<typename T>
class F {
T f;
public:
F(T t){
f = t;
}
T& operator()(){
return f;
}
};
int main()
{
int x = 5;
F<int (*)(int, int)> f( [x](int a, int b){return a+b;} );
return 0;
}
The compiler says
error: no matching function for call to 'F<int (*)(int, int)>::F(main()::<lambda(int, int)>)'
F<int (*)(int, int)> f( [x](int a, int b){return a+b;} );
It's more complicated... Internally lambda functions that capture variables are not functions as such, are data structures. I not found any solution developed and many requests and questions unresolved, then I developed this minimal code to wrap lambda pointer not using std::function or any other standard function or dependence. Pure c++11.
Accepts all kinds of lambda captures, arguments by reference, return void, and supports top level functions and member methods.
// Type checkers
template<typename _Type>
struct IsVoid
{
static const bool value = false;
};
template<>
struct IsVoid<void>
{
static const bool value = true;
};
// Callable signature interfce
template<typename _ReturnType, typename..._ArgTypes>
struct Callable
{
typedef _ReturnType ReturnType;
typedef _ReturnType (*SignatureType)(_ArgTypes...);
virtual _ReturnType operator()(_ArgTypes...args) = 0;
};
// Function and lambda closure wrapper
template<typename _ClosureType, typename _ReturnType, typename..._ArgTypes>
struct Closure: public Callable<_ReturnType, _ArgTypes...>
{
typedef _ClosureType ClosureType;
const _ClosureType closureHandler;
Closure(const _ClosureType& handler)
: closureHandler(handler)
{
}
_ReturnType operator()(_ArgTypes...args) override
{
if(IsVoid<_ReturnType>::value)
closureHandler(args...);
else
return closureHandler(args...);
}
};
// Fuction template selector
template <typename _FunctionType>
class Function
: public Function<decltype(&_FunctionType::operator())>
{
};
// Function, lambda, functor...
template <typename _ReturnType, typename... _ArgTypes>
class Function<_ReturnType(*)(_ArgTypes...)>
{
public:
typedef Function<_ReturnType(*)(_ArgTypes...)> SelfType;
typedef _ReturnType(*SignatureType)(_ArgTypes...);
Callable<_ReturnType, _ArgTypes...>* callableClosure;
Function(_ReturnType(*function)(_ArgTypes...))
: callableClosure(new Closure<SignatureType, _ReturnType, _ArgTypes...>(function))
{
}
// Captured lambda specialization
template<typename _ClosureType>
Function(const _ClosureType& function)
: callableClosure(new Closure<decltype(function), _ReturnType, _ArgTypes...>(function))
{
}
_ReturnType operator()(_ArgTypes... args)
{
if(IsVoid<_ReturnType>::value)
(*callableClosure)(args...);
else
return (*callableClosure)(args...);
}
};
// Member method
template <typename _ClassType, typename _ReturnType, typename... _ArgTypes>
class Function<_ReturnType(_ClassType::*)(_ArgTypes...)>
{
public:
typedef Function<_ReturnType(_ClassType::*)(_ArgTypes...)> SelfType;
typedef _ReturnType(_ClassType::*SignatureType)(_ArgTypes...);
SignatureType methodSignature;
Function(_ReturnType(_ClassType::*method)(_ArgTypes...))
: methodSignature(method)
{
}
_ReturnType operator()(_ClassType* object, _ArgTypes... args)
{
if(IsVoid<_ReturnType>::value)
(object->*methodSignature)(args...);
else
return (object->*methodSignature)(args...);
}
};
// Const member method
template <typename _ClassType, typename _ReturnType, typename... _ArgTypes>
class Function<_ReturnType(_ClassType::*)(_ArgTypes...) const>
{
public:
typedef Function<_ReturnType(_ClassType::*)(_ArgTypes...) const> SelfType;
typedef _ReturnType(_ClassType::*SignatureType)(_ArgTypes...) const;
SignatureType methodSignature;
Function(_ReturnType(_ClassType::*method)(_ArgTypes...) const)
: methodSignature(method)
{
}
_ReturnType operator()(_ClassType* object, _ArgTypes... args)
{
if(IsVoid<_ReturnType>::value)
(object->*methodSignature)(args...);
else
return (object->*methodSignature)(args...);
}
};
Tests:
#include <iostream>
class Foo
{
public:
int bar(int a, int b)
{
return a + b;
}
};
int someFunction(int a, int b)
{
return a + b;
}
int main(int argc, char** argv)
{
int a = 10;
int b = 1;
// Lambda without capturing
Function<int(*)(int)> fn1([] (int b) -> int {
return b;
});
std::cout << fn1(2) << std::endl; // 2
// Lambda capturing variable
Function<int(*)(int)> fn2([a] (int c) -> int {
return a + c;
});
std::cout << fn2(-7) << std::endl; // 3
// Lambda capturing scope
Function<int(*)(int)> fn3([&] (int c) -> int {
return a + c;
});
std::cout << fn3(-5) << std::endl; // 5
// Arguments by reference
Function<void(*)(int&, int)> fn4([] (int& d, int f) {
d = d + f;
});
fn4(a, -3); // Void call
std::cout << a << std::endl; // 7
// Top level function reference
Function<int(*)(int, int)> fn6(someFunction);
std::cout << fn6(a, 4) << std::endl; // 11
// Member method
Foo* foo = new Foo();
Function<int(Foo::*)(int,int)> fn7(foo->bar);
std::cout << fn7(foo, a, 8) << std::endl; // 15
}
Works correctly wih gcc 4.9.
Thanks for your question.
A lambda can't directly be converted to a free function pointer if it captures something just because they are two different things.
A lambda with capturing values must save its state somewhere, but a function pointer is just a memory address thus it doesn't provide that functionality. So you would be allowed to do something
static_cast<int(*)(int,int)>([](int a, int b) { return a+b; })
but that's not your case.
Some solutions could be:
don't use a function pointer but use a std::function<int(int,int>) instead
provide a free function which invokes the lambda (not a good solution in your case, mostly meant to be used to inerface with legacy code I'd say
use a template function which provides the wrapping from lambda to function pointer by itself. Similar to the solution proposed here
Use simple workaround with decltype.
auto lambda = [x](int a, int b){return a+b;};
F<decltype(lambda)> f(lambda); // OK
To make it look concise, we can use macro:
#define DECLARE_F(OBJECT, LAMBDA) \
auto lambda = LAMBDA; \
F<decltype(lambda)> OBJECT(lambda)
Usage:
DECLARE_F(f, [x](int a, int b){return a+b;}); // 1 per line if used ## __LINE__
I would like to be able to name to a templated function in a template.
Since one can name a templated class using the "template template" syntax, and since one can name a function using the "function pointer" syntax, I was wondering whether there is a syntax (or a proposal) to name a function in a template without specifying to templates.
template<typename t_type>
struct A {
t_type value;
};
template<template<typename> class t_type>
struct B {
t_type<int> value;
};
template<int added>
constexpr int C (int value) {
return value + added;
}
template<int (*function)(int)>
constexpr int D (int value) {
return function(value);
}
// GOAL: Template argument referring to templated function
/*template<template<int> int (*function)(int)>
constexpr int E (int value) {
return function<1>(value);
}*/
int main() {
B<A> tt_good;
int fp_good = D< &C<1> >(0);
/*int fp_fail = E< &C >(0);*/
return 0;
}
One possible work-around for anyone interested in this functionality to first wrap the function D in a struct with a call method named (for example) "method", pass the struct into E as a "template template" parameter, and then call "method" in E.
The reason that I don't like this approach is that it requires a wrapper structure for every variadic function that might be used in this way.
Unfortunately, you cannot pass function templates as template parameters. The closest you can get is by using generic functors:
#include <iostream>
template <typename F>
void call(F f)
{
f("hello, world\n");
}
int main()
{
call([](auto value) { std::cout << value; });
}
If you don't have C++14 generic lambdas, you can write your own functors by hand:
#include <iostream>
template <typename F>
void call(F f)
{
f("hello, world\n");
}
struct print
{
template <typename T>
void operator()(T value) const
{
std::cout << value;
}
};
int main()
{
call(print());
}