I'd like to create a class that accepts a function which was created by another function in Arduino. The "closest" I got after searching and a lot of trial and error (without std::function
as we're in Arduino and C++ 14):
in foo.h
class Foo {
private:
template<typename Functor>
Functor _lambda;
public:
template<typename Functor>
Foo(Functor lambda);
static auto create_lambda(int a) {
return [a](int b) mutable { ... }
}
};
in foo.cpp
template<typename Functor>
Foo::Foo (Functor lambda) : _lambda(lambda) {}
in bar.cpp
new Foo(Foo::create_lambda(2));
The code above produces a number of errors including:
error: data member '_lambda' cannot be a member template
error: 'Foo::Foo(Functor) [with Functor = Foo::create_lambda(int)::<lambda(bool)>]', declared using local type 'Foo::create_lambda(int)::<lambda(bool)>', is used but never defined
Also, happy to go with C++ 17 if that helps.
The class has to be templated, rather than the member:
// Put this whole thing in the header file.
// It has to go there b/c templates have to be in the header.
template<class F>
class Foo {
F func;
public:
Foo() = default;
Foo(Foo const&) = default;
Foo(Foo&&) = default;
Foo(F f) : func(f) {}
// Example invoke member function
int invoke(int value) {
return func(value);
}
};
In C++17, we can make it figure out the type of F
automatically when making a Foo
by adding a template deduction guide for Foo
:
// Put this after the class declaration
template <class F>
Foo(F) -> Foo<F>;
Then, we can use it pretty easily!
// Template parameter is implicit
Foo myFoo = [](int x) { return x * x; };
// myFoo now has type Foo<(anonymous lambda)>
If you absolutely need runtime polymorphism, you can have an interface that each Foo<F>
extends:
class Invokable {
virtual int invoke(int) = 0;
virtual ~Invokable() = default;
};
template <class F>
class Foo : Invokable {
// ...
};
This article about the way std::function
is implemented provides more details than I can in a stack overflow post: https://shaharmike.com/cpp/naive-std-function/
Addendum: You can see a working example here.
When compiled with optimization, the assembly is extremely compact. One of the benefits of C++ is that there's no overhead in using lambdas or templates, and they're entirely transparent to the compiler.
(Virtual functions are NOT transparent, which is why I do my best to avoid them, but sometimes you really need runtime polymorphism)
.LC0:
.string "The square of %i is %i\n"
main:
push rbx
xor ebx, ebx
.L2:
mov edx, ebx
mov esi, ebx
mov edi, OFFSET FLAT:.LC0
xor eax, eax
imul edx, ebx
add ebx, 1
call printf
cmp ebx, 11
jne .L2
xor eax, eax
pop rbx
ret
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.