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

Utility class for robust EBO

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

Problem

In modern C++, many classes accept a policy type as a template parameter. The author of the class does not know in advance what kind of policy its class will be instantiated with. If the policy class is empty, it would be desirable to inherit from it so to leverage the empty base optimization (EBO). On the other hand, not every type can be inherited from. Counter-examples include unions, classes declared as final or non-class types like int.

I wrote the following utility policy_base_t that allows library authors to make use of EBO when it is possible to inherit from T and fall back to delegation otherwise. It will always be possible to inherit from policy_base_t itself. A reference to the policy object may be obtained via the (protected) policy member function.

```
#ifndef META_HXX
#define META_HXX

#include
#include

namespace meta
{

namespace detail
{

template
class deriving_policy : private PolicyT
{

protected:

template
deriving_policy(ArgTs&&... args)
noexcept(noexcept(PolicyT (std::declval()...))) :
PolicyT (std::forward(args)...)
{
}

PolicyT&
policy() noexcept
{
return *this;
}

const PolicyT&
policy() const noexcept
{
return *this;
}

};

template
class delegating_policy
{

private:

PolicyT policy_; // not initialized

protected:

template
delegating_policy(ArgTs&&... args)
noexcept(noexcept(PolicyT (std::declval()...))) :
policy_ (std::forward(args)...)
{
}

PolicyT&
policy() noexcept
{
return this->policy_;
}

const PolicyT&
policy() const noexcept
{
return this->policy_;
}

};

} // namespace detail

template
using policy_base_t = typename std::conditional
::value && !std::is_final::value),
detail::deriving_policy,
detail::delegating_policy
>:

Solution

Code looks fine, I have one important issue and some minor comments:

Typedefs

One of the common uses of policy classes are their typedefs (cf. std::iterator<>). Using policy_base_t hides all of those, since in the delegating case, you hid P, and in the deriving case, you inherited privately. So I would suggest at the very least deriving publically from PolicyT and exposing it as a typedef in both cases:

using Policy = PolicyT;


That at least would handle most of the cases. Presumably nobody is adding typedefs to their final policy right?

Inherit constructors too

Rather than explicitly forwarding args to the constructor in deriving_policy, you could just using PolicyT::PolicyT; Does the same thing and saves a bunch of typing.

Unecessary this->

In delegating_policy, you don't need this-> where you use it, you can just write policy_. It's a member, so it's not dependent.

Excessive vertical spacing

You don't need to double space around accessor labels or namespaces. It just makes it harder to fit everything on one window.

Use the aliases

Prefer the C++14 std::conditional_t to typename std::conditional::type. If you don't have a C++14 compiler, write the alias somewhere and still use it.

Code Snippets

using Policy = PolicyT;

Context

StackExchange Code Review Q#114065, answer score: 5

Revisions (0)

No revisions yet.