HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppModerate

Impossibly fast delegate in C++11

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
fastimpossiblydelegate

Problem

This legendary C++ delegate article can be easily converted into C++11, without the need for fancy preprocessor magic in the original. I'd like to know if I got all the necessary C++11 nuances right. Suggestions?

```
#pragma once
#ifndef DELEGATE_HPP
# define DELEGATE_HPP

#include

#include

#include

#include

#include

template class delegate;

template
class delegate
{
using stub_ptr_type = R ()(void, A&&...);

delegate(void* const o, stub_ptr_type const m) noexcept :
object_ptr_(o),
stub_ptr_(m)
{
}

public:
delegate() = default;

delegate(delegate const&) = default;

delegate(delegate&&) = default;

delegate(::std::nullptr_t const) noexcept : delegate() { }

template {}>::type>
explicit delegate(C const* const o) noexcept :
object_ptr_(const_cast(o))
{
}

template {}>::type>
explicit delegate(C const& o) noexcept :
object_ptr_(const_cast(&o))
{
}

template
delegate(C const object_ptr, R (C:: const method_ptr)(A...))
{
*this = from(object_ptr, method_ptr);
}

template
delegate(C const object_ptr, R (C:: const method_ptr)(A...) const)
{
*this = from(object_ptr, method_ptr);
}

template
delegate(C& object, R (C::* const method_ptr)(A...))
{
*this = from(object, method_ptr);
}

template
delegate(C const& object, R (C::* const method_ptr)(A...) const)
{
*this = from(object, method_ptr);
}

template ::type>{}
>::type
>
delegate(T&& f) :
store_(operator new(sizeof(typename ::std::decay::type)),
functor_deleter::type>),
store_size_(sizeof(typename ::std::decay::type))
{
using functor_type = typename ::std::decay::type;

new (store_.get()) functor_type(::std::forward(f));

object_ptr_ = store_.get();

stub_ptr_ = functor_stub;

deleter_ = deleter_stub;
}

delegate& operator=(delegate const&) = default;

delegate& operator=(delegate&&) = default;

template
delegate& operator=(R (C::* const rhs)(A...))

Solution

It looks by and large OK. Just some nitpicks

-
the default constructor could just be delegate() = default;, or otherwise initialize all members... or remove it entirely if it makes no sense.

-
the copy constructor should use initialization, not assignment.

-
swap should return void.

-
Assignment should pass-by-value:

delegate& operator=(delegate rhs) { rhs.swap(*this); return *this; }


-
Invocation should use arbitrary arguments and forwarding:

template 
R operator()(B &&... b)
{
    return (*stub_ptr)(object_ptr, std::forward(b)...);
}


In fact, you should add enable_if with some variadic version of is_constructible... to the operator so you don't create impossible overloads.

Code Snippets

delegate& operator=(delegate rhs) { rhs.swap(*this); return *this; }
template <typename ...B>
R operator()(B &&... b)
{
    return (*stub_ptr)(object_ptr, std::forward<B>(b)...);
}

Context

StackExchange Code Review Q#14730, answer score: 15

Revisions (0)

No revisions yet.