Default argument with template in C++ - c++

I'm designing an interface, by which users can define a class that tells what they want to do.
The code is something like the following,
#include <stdio.h>
class Dummy{
public:
void do(){ printf("do nothing\n"); }
};
class Task{
public:
void do(){ printf("do something\n"); }
};
template <class TASK>
void func(TASK &task = Dummy()){
task.do();
}
int main(){
func(); // do nothing
Task task;
func(task); // do something
}
How to make it work?

The main issue is this func argument:
TASK &task = Dummy()
It will not work unless it is const. This happens because non-const lvalue reference to type cannot bind to a temporary.
But if you can use const there, you can easily solve your problem:
class Dummy{
public:
void doit() const { printf("do nothing\n"); }
};
class Task{
public:
void doit() const { printf("do something\n"); }
};
template <class TASK = Dummy>
void func(const TASK &task = TASK()){
task.doit();
}
int main(){
func(); // do nothing
Task task;
func(task); // do something
}

For starters, don't have an identifier (function named) named do, since do is a language keyword. Using it as an identifier is a diagnosable error. There's no option other than changing the name of the function.
Second, the argument will of func() will need to be const, since the default value being passed is a temporary (which can only be bound to a const reference). This also means your function in the classes needs to be const qualified.
Third, when calling func() it is necessary to either pass SOME information so the compiler can work out how to instantiate the template. If you want to pass no information at all at the call site (i.e. func()) then you need to have a non-templated overload.
Fourth, use C++ streams rather than C I/O.
class Dummy
{
public:
void do_it() const { std::cout << "do nothing\n"; }
};
class Task
{
public:
void do_it() const { std::cout << "do something\n"; }
};
template <class TASK>
void func(const TASK &task)
{
task.do_it();
}
void func()
{
func(Dummy());
}
int main()
{
func(); // do nothing
Task task;
func(task); // do something
}
Option 2 is to replace the two versions of func() above with
template <class TASK = Dummy>
void func(const TASK &task = TASK())
{
task.do_it();
}

Related

Pass member function as argument

I have a function that runs a callback:
void run_callback(void(*callback)(uint32_t)) {
callback(100);
}
This works with static functions,
void global_callback(uint32_t);
int main() {
run_callback(global_callback);
}
but not with member functions.
class A {
int x;
public:
void callback(uint32_t);
};
int main() {
A foo;
run_callback(foo.callback);
}
I work around this with a static wrapper function.
void run_member_callback(void* obj, void(*callback)(void*,uint32_t)) {
callback(obj, 100);
}
class B {
int x;
public:
static void static_callback(void* obj, uint32_t value) {
static_cast<B*>(obj)->callback(value);
}
void callback(uint32_t);
};
int main() {
B foo;
run_member_callback(&foo, foo.static_callback);
}
Is there a simple way to pass a member function as an argument?
edit:
I'm trying to avoid STL, and templates aren't an option since my implementation of run_callback is virtual.
You are doing some weird, C-ish things. Use C++ features. I personally would use a template for run_callback and a lambda for passing the member function:
template <class F>
void run_callback(F callback)
{
callback(100);
}
class A
{
int x;
public:
void callback(uint32_t);
};
int main()
{
A foo{};
run_callback([&](uint32_t a) { return foo.callback(a); });
}
If you capture the object by reference take care it outlives the run_callback call. Otherwise capture it by value.
What is a lambda expression in C++11?

Callback using lambda with closures

I'm trying to implement a callback which passes control from an Interrupt Service Routine to a member function on a c++ class. I thought lambdas and closures would be a convenient means of doing this, but I'm having trouble implementing it. Below is a simplified version of my code.
The issue I'm stuck on is how to store the "function pointer" to the "lambda".
class Gpio
{
public:
typedef void (*ExtiHandler)();
private:
ExtiHandler handler;
public:
void enable_irq(ExtiHandler handler_in)
{
// enable interrupt
// ...
// save handler so callback can be issued later
handler = handler_in;
}
};
class Button
{
private:
Gpio& pin;
public:
Button(Gpio& pin_in) : pin(pin_in)
{
};
void button_pressed()
{
// do something
}
void init()
{
pin.enable_irq([this]() { this->button_pressed(); });
}
};
Compiling fails with the following error message;
no matching function for call to 'Gpio::enable_irq(Button::init()::<lambda()>)'candidate: void Gpio::enable_irq(Gpio::ExtiHandler) no known conversion for argument 1 from 'Button::init()::<lambda()>' to 'Gpio::ExtiHandler {aka void (*)()}' Build failed
How can I modify this code to resolve the compile error?
The problem is, that enable_irq function expects a typed function pointer of type void (*ExtiHandler)() not a lambda function.
That means, here
pin.enable_irq([this]() { this->button_pressed(); });
you are trying to store a lambda function(with capturing the instance) to a typed function pointer. You could have converted the lambda to a function pointer(easily) if it would have been a capture-less lambda.
See [expr.prim.lambda.closure] (sec 7)
The closure type for a non-generic lambda-expression with no
lambda-capture whose constraints (if any) are satisfied has a
conversion function to pointer to function with C++ language linkage
having the same parameter and return types as the closure type's
function call operator.
Since lambdas are not just ordinary functions and capturing it need to preserve a state,
you can not find any simple or conventional solution to make them assign to function pointers.
Solution - 1
The simplest solution is to use std::function instead, by paying some type erasure overhead. That means, in your code, just need to change the
typedef void(*ExtiHandler)();
to
typedef std::function<void()> ExtiHandler;
// or
// using ExtiHandler = std::function<void()>;
Solution - 2
Can this be accomplished without using the STL?
Yes. After making a small research on this topic, I came up with a type traits solution to store the lambdas with closure to the equivalent typed function pointer.
#include <iostream>
template<typename Lambda> struct convert_lambda : convert_lambda<decltype(&Lambda::operator())> {};
template<typename Lambda, typename ReType, typename... Args>
struct convert_lambda<ReType(Lambda::*)(Args...) const>
{
using funPtr = ReType(*)(Args...);
static funPtr make_function_ptr(const Lambda& t)
{
static const Lambda& lmda = t;
return [](Args... args) { return lmda(args...); };
}
};
template<typename Lambda> using convert_lambda_t = typename convert_lambda<Lambda>::funPtr;
template<typename Lambda> constexpr convert_lambda_t<Lambda> make_function_ptr(const Lambda& t)
{
return convert_lambda<Lambda>::make_function_ptr(t);
}
Usage: SEE LIVE EXAMPLE
You can now simply continue with your Gpio and Button classes, without
changing anything.:
pin.enable_irq(make_function_ptr([this]() { this->button_pressed(); }));
// or
// pin.enable_irq(make_function_ptr([&]() { this->button_pressed();}));
Or with arguments. For example
int aa = 4;
auto lmda = [&aa](const int a, const float f) { std::cout << a * aa * f << std::endl; };
void(*fPtrTest)(const int, const float) = make_function_ptr(lmda);
fPtrTest(1, 2.0f);
Drawbacks: The solution - 2:
is not capable of recognizing the optional sequence of specifiers.(i.e, mutable, constexpr)
is not capable of forwarding parameter pack to the traits. i.e,
the following is not possible:
return [](Args&&... args) { return lmda(std::forward<Args>(args)...); };
Closure object can be assigned to function pointer only if capture list of lambda is empty, in your case this condition is not met - [this].
You can use std::function as wrapper to store your closures:
#include <functional>
class Gpio
{
public:
using ExtiHandler = std::function<void()>;
private:
std::function<void()> handler;
public:
void enable_irq(const ExtiHandler& handler_in)
{
handler = handler_in;
}
};
If you don't have std library then you could implement the type erasure yourself.
Something like this ...
#include <iostream>
#include <memory>
struct function
{
struct base
{
virtual void call() = 0;
virtual base* clone() = 0;
};
template <typename Fn>
struct impl : base
{
Fn fn_;
impl(Fn&& fn) : fn_(std::forward<Fn>(fn)){}
impl(Fn& fn) : fn_(fn){}
virtual void call()
{
fn_();
}
virtual base* clone() { return new impl<Fn>(fn_); }
};
base* holder_;
function() : holder_(nullptr)
{};
template <typename Fn>
function(Fn&& fn) : holder_(nullptr)
{
holder_ = new impl<Fn>(std::forward<Fn>(fn));
}
function( function&& other)
{
holder_ = other.holder_;
other.holder_ = nullptr;
}
function(const function& other)
{
holder_ = other.holder_->clone();
}
~function()
{
if (holder_) delete holder_;
}
function& operator=(function&& other)
{
if (holder_) delete holder_;
holder_ = other.holder_;
other.holder_ = nullptr;
return *this;
}
function& operator=(const function& other)
{
if (holder_) delete holder_;
holder_ = other.holder_->clone();
return *this;
}
void operator()()
{
holder_->call();
}
};
class Gpio
{
public:
using ExtiHandler = function;
//private:
ExtiHandler handler;
//public:
void enable_irq(ExtiHandler handler_in)
{
// enable interrupt
// ...
// save handler so callback can be issued later
handler = handler_in;
}
};
class Button
{
private:
Gpio& pin;
public:
Button(Gpio& pin_in) : pin(pin_in)
{
};
void button_pressed()
{
std::cout << "Button pressed" << std::endl;
}
void init()
{
pin.enable_irq([this]() { this->button_pressed(); });
}
};
int main() {
Gpio some_pin;
Button b(some_pin);
b.init();
some_pin.handler();
return 0;
}
Demo

Copy-construct and later access arbitrary POD types

I'd like to fill in the store() and launch() methods in the below code. The important detail which captures the spirit of the problem is that the object foo declared in main() no longer exists at the time we call launch(). How can I do this?
#include <cstdio>
#include <cstring>
#include <type_traits>
template<typename T, typename U=
typename std::enable_if<std::is_trivially_copyable<T>::value,T>::type>
struct Launchable {
void launch() { /* some code here */ }
T t;
// other members as needed to support DelayedLauncher
};
class DelayedLauncher {
public:
template<typename T>
void store(const Launchable<T>& t) {
// copy-construct/memcpy t into some storage
}
void launch() const {
// call t.launch(), where t is (a copy of) the last value passed into store()
}
// other members as needed
};
int main() {
DelayedLauncher launcher;
{
Launchable<int> foo;
launcher.store(foo);
}
launcher.launch(); // calls foo.launch()
return 0;
}
Note that if we only had a fixed set of N types to pass into store(), we could achieve the desired functionality by declaring N Launchable<T> fields and N non-template store() methods, one for each type, along with an enum field whose value is use in a switch statement in the launch() method. But I'm looking for an implementation of DelayedLauncher that will not need modification as more Launchable types are added.
using std::function:
class DelayedLauncher {
public:
template<typename T>
void store(const Launchable<T>& t) {
f = [t]() {t.launch();};
}
void launch() const { f(); }
private:
std::function<void()> f;
};
You could give Launchable a base class with a virtual launch() and no template, and store pointers to that base class in Launcher::store.
EDIT: Adapted from #dshin's solution:
struct LaunchableBase {
virtual void launch() = 0;
};
template<typename T, typename U=
typename std::enable_if<std::is_trivially_copyable<T>::value,T>::type>
struct Launchable : public LaunchableBase {
virtual void launch() override { /* some code here */ }
T t;
// other members as needed to support DelayedLauncher
};
class DelayedLauncher {
public:
template<typename T>
void store(const Launchable<T>& t) {
static_assert(sizeof(t) <= sizeof(obj_buffer),
"insufficient obj_buffer size");
static_assert(std::is_trivially_destructible<T>::value,
"leak would occur with current impl");
p = new (obj_buffer) Launchable<T>(t);
}
void launch() const {
p->launch();
}
private:
char obj_buffer[1024]; // static_assert inside store() protects us from overflow
LaunchableBase *p;
};
I believe this variant of Jarod42's solution will avoid dynamic allocation, although I would appreciate if someone could confirm that this will work the way I think it will:
class DelayedLauncher {
public:
template<typename T>
void store(const Launchable<T>& t) {
static_assert(sizeof(t) <= sizeof(obj_buffer),
"insufficient obj_buffer size");
static_assert(std::is_trivially_destructible<T>::value,
"leak would occur with current impl");
auto p = new (obj_buffer) Launchable<T>(t);
auto ref = std::ref(*p);
f = [=]() {ref.get().launch();};
}
void launch() const {
f();
}
private:
char obj_buffer[1024]; // static_assert inside store() protects us from overflow
std::function<void()> f;
};
I believe it should work because the resources I've looked at indicate that std::function implementations typically have a "small capture" optimization, only triggering a dynamic allocation if the total size of the captured data exceeds some threshold.
EDIT: I replaced my code with a version provided by Jarod42 in the comments. The standard guarantees the above implementation will not trigger dynamic allocation.

functors + member pointers to create signal object

I have this code:
// signal supporter parent
class signalable {};
template <class typeT = signalable>
typedef void (typeT::*trig)(std::string);
template <class typeT = signalable>
class trigger
{
private:
typeT* instance;
typeT::trig fun;
public:
trigger(typeT* inst, typeT::trig function)
: instance(inst), fun(function)
{}
void operator ()(std::string param)
{
(instance->*fun)(param);
}
};
And I get lots of compile error that I bet pros know of. I'm just confused a little bit about this context.
What I want to do is clear: Pass pointer to an object, and pointer to one of it's member functions, to make a functor and pass it over in my program.
Would appreciate your helps and "corrections".
Thank you!
Are you trying to do something like this?
#include <string>
#include <iostream>
// signal supporter parent
class signalable
{
public:
void foo(std::string s) { std::cout << "hello: " << s << std::endl; }
};
template <class typeT = signalable>
class trigger
{
typedef void (typeT::*trig)(std::string);
private:
typeT* instance;
trig fun;
public:
trigger(typeT* inst, trig function)
: instance(inst), fun(function)
{}
void operator ()(std::string param)
{
(instance->*fun)(param);
}
};
int main()
{
signalable s;
trigger<> t(&s, &signalable::foo);
t("world");
}
As for some of the more specific errors in your code, most of them seem to relate to your typedef. C++11 allows "template typedefs", but they don't look like that. Have a look at this thread for an example of template typedefs:
C++ template typedef

Template type deduction with a non-copyable class

Suppose I have an autolocker class which looks something like this:
template <T>
class autolocker {
public:
autolocker(T *l) : lock(l) {
lock->lock();
}
~autolocker() {
lock->unlock();
}
private:
autolocker(const autolocker&);
autolocker& operator=(const autolocker&);
private:
T *lock;
};
Obviously the goal is to be able to use this autolocker with anything that has a lock/unlock method without resorting to virtual functions.
Currently, it's simple enough to use like this:
autolocker<some_lock_t> lock(&my_lock); // my_lock is of type "some_lock_t"
but it is illegal to do:
autolocker lock(&my_lock); // this would be ideal
Is there anyway to get template type deduction to play nice with this (keep in my autolocker is non-copyable). Or is it just easiest to just specify the type?
Yes you can use the scope-guard technique
struct autolocker_base {
autolocker_base() { }
protected:
// ensure users can't copy-as it
autolocker_base(autolocker_base const&)
{ }
autolocker_base &operator=(autolocker_base const&)
{ return *this; }
};
template <T>
class autolocker : public autolocker_base {
public:
autolocker(T *l) : lock(l) {
lock->lock();
}
autolocker(const autolocker& o)
:autolocker_base(o), lock(o.lock)
{ o.lock = 0; }
~autolocker() {
if(lock)
lock->unlock();
}
private:
autolocker& operator=(const autolocker&);
private:
mutable T *lock;
};
Then write a function creating the autolocker
template<typename T>
autolocker<T> makelocker(T *l) {
return autolocker<T>(l);
}
typedef autolocker_base const& autolocker_t;
You can then write it like this:
autolocker_t lock = makelocker(&my_lock);
Once the const reference goes out of scope, the destructor is called. It doesn't need to be virtual. At least GCC optimizes this quite well.
Sadly, this means you have to make your locker-object copyable since you need to return it from the maker function. But the old object won't try to unlock twice, because its pointer is set to 0 when it's copied, so it's safe.
Obviously you can't get away with autolocker being a template, because you want to use it as a type, and templates must be instantiated in order to obtain types.
But type-erasure might be used to do what you want. You turn the class template into a class and its constructor into a member template. But then you'd have to dynamically allocate an inner implementation object.
Better, store a pointer to a function that performs the unlock and let that function be an instance of a template chosen by the templatized constructor. Something along these lines:
// Comeau compiles this, but I haven't tested it.
class autolocker {
public:
template< typename T >
autolocker(T *l) : lock_(l), unlock_(&unlock<T>) { l->lock(); }
~autolocker() { unlock_(lock_); }
private:
autolocker(const autolocker&);
autolocker& operator=(const autolocker&);
private:
typedef void (*unlocker_func_)(void*);
void *lock_;
unlocker_func_ unlock_;
template <typename T>
static void unlock(void* lock) { ((T*)lock)->unlock(); }
};
I haven't actually tried this and the syntax might be wrong (I'm not sure how to take the address of a specific function template instance), but I think this should be doable in principle. Maybe someone comes along and fixes what I got wrong.
I like this a lot more than the scope guard, which, for some reason, I never really liked at all.
I think jwismar is correct and what you want is not possible with C++. However, a similar (not direct analogue) construct is possible with C++0x, using several new features (rvalues/moving and auto variable type):
#include <iostream>
template <typename T>
class autolocker_impl
{
public:
autolocker_impl(T *l) : lock(l) {
lock->lock();
}
autolocker_impl (autolocker_impl&& that)
: lock (that.lock)
{
that.lock = 0;
}
~autolocker_impl() {
if (lock)
lock->unlock();
}
private:
autolocker_impl(const autolocker_impl&);
autolocker_impl& operator=(const autolocker_impl&);
private:
T *lock;
};
template <typename T>
autolocker_impl <T>
autolocker (T* lock)
{
return autolocker_impl <T> (lock);
}
struct lock_type
{
void lock ()
{ std::cout << "locked\n"; }
void unlock ()
{ std::cout << "unlocked\n"; }
};
int
main ()
{
lock_type l;
auto x = autolocker (&l);
}
autolocker is a class template, not a class. Your "this would be ideal" is showing something that doesn't make sense in C++.