patterncppModerate
Impossibly fast delegate in C++11
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...))
```
#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
-
the copy constructor should use initialization, not assignment.
-
-
Assignment should pass-by-value:
-
Invocation should use arbitrary arguments and forwarding:
In fact, you should add
-
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.