MoReFEM
Loading...
Searching...
No Matches
Public Types | Public Member Functions | Static Public Attributes | Private Types | Private Attributes
MoReFEM::StrongType< T, Parameter, Skills > Class Template Reference

Abstract class used to define a StrongType, which allows more expressive code and ensures that the order of arguments of the same underlying type is respected at call sites. More...

#include <StrongType.hpp>

Inheritance diagram for MoReFEM::StrongType< T, Parameter, Skills >:
Collaboration diagram for MoReFEM::StrongType< T, Parameter, Skills >:

Public Types

using underlying_type = T
 Convenient alias.
 

Public Member Functions

 operator T () const noexcept
 
T const & Get () const noexcept
 Constant accessor to the underlying value held by the strong type.
 
T & Get () noexcept
 Non constant accessor to the underlying value held by the strong type.
 
Special members.
constexpr StrongType (T const &value)
 Constructor.
 
template<class T_ = T>
constexpr StrongType (T &&value, std::enable_if_t<!std::is_reference< T_ >{}, std::nullptr_t >=nullptr)
 Move constructor.
 
template<class T_ = T>
constexpr StrongType (std::enable_if_t< typename almost_self< T_ >::enable_default_constructor{}, std::nullptr_t >=nullptr)
 Default constructor, which is defined only when enable_default_constructor is defined.
 
 ~StrongType ()=default
 Destructor.
 
 StrongType (const StrongType &rhs)=default
 The copy constructor.
 
 StrongType (StrongType &&rhs)=default
 The move constructor.
 
StrongTypeoperator= (const StrongType &rhs)=default
 The (copy) operator=.
 
StrongTypeoperator= (StrongType &&rhs)=default
 The (move) operator=.
 

Static Public Attributes

static constexpr bool IsStrongType { true }
 Traits to indicate the object is a strong type.
 

Private Types

template<class T_ >
using almost_self = StrongType<T_, Parameter, Skills...>
 

Private Attributes

value_
 Underlying value held by the strong type.
 

Detailed Description

template<class T, class Parameter, template< typename > class... Skills>
class MoReFEM::StrongType< T, Parameter, Skills >

Abstract class used to define a StrongType, which allows more expressive code and ensures that the order of arguments of the same underlying type is respected at call sites.

Adapted from https://github.com/joboccara/NamedType/

Template Parameters
TType of the parameter.
ParameterThis is a phantom type used to specialize the type deduced for SrongType, it is not actually used in the implementation.
SkillsOptional arguments to grant additional functionalities to the created StrongType (see below and https://www.fluentcpp.com/2017/05/23/strong-types-inheriting-functionalities-from-underlying/ post).

As an example we could create a class Rectangle with strong types to differentiate its width from its length as:

class StrongRectangle
{
public:
StrongRectangle (Width width, Height height) : width_(width.Get()), height_(height.Get()) {}
double getWidth() const {return width_;}
double getHeight() const {return height_;}
private:
double width_;
double height_;
};
Abstract class used to define a StrongType, which allows more expressive code and ensures that the or...
Definition StrongType.hpp:101

At the calling site we would have:

StrongRectangle rectangle((Width(5.0)), (Height((2.0))));

Note that the extra parenthesis are only required for constructors due to the most vexing parse.

As for Skills: a StrongType does not allow direct operations upon its instances. For instance the following code is invalid:

Width w1(5.);
Width w2(10.);
Width sum = w1 + w2; // does not compile!

The new arguments enable to add support for it; to do so we provide a new Crtp (called Addable here) which grants support for operator+:

Width w1(5.);
Width w2(10.);
Width sum = w1 + w2; // ok!

The list of possible options is in the 'Skills' subdirectory; you may define your own if needed (it is basically a Crtp). Several may be added in the declaration:

Member Typedef Documentation

◆ almost_self

template<class T , class Parameter , template< typename > class... Skills>
template<class T_ >
using MoReFEM::StrongType< T, Parameter, Skills >::almost_self = StrongType<T_, Parameter, Skills...>
private

An alias to the class type... except the T parameter is not fixed. Useful for one constructor which is defined only if specific conditions are met (through std::enable_if_t). This code was written before C++ 20 was mainstream enough to be used within the code; its 'require' would of course greatly simplified such constructor definitions and this trick wouldn't be required at all.

Constructor & Destructor Documentation

◆ StrongType() [1/5]

template<class T , class Parameter , template< typename > class... Skills>
constexpr MoReFEM::StrongType< T, Parameter, Skills >::StrongType ( T const & value)
explicitconstexpr

Constructor.

Parameters
[in]valueUnderlying value held by the strong type.

◆ StrongType() [2/5]

template<class T , class Parameter , template< typename > class... Skills>
template<class T_ = T>
constexpr MoReFEM::StrongType< T, Parameter, Skills >::StrongType ( T && value,
std::enable_if_t<!std::is_reference< T_ >{}, std::nullptr_t > = nullptr )
explicitconstexpr

Move constructor.

Parameters
[in]valueUnderlying value held by the strong type.
Template Parameters
T_ArtificIal template parameter to ensure that SFINAE applies in case T is a reference.

◆ StrongType() [3/5]

template<class T , class Parameter , template< typename > class... Skills>
template<class T_ = T>
constexpr MoReFEM::StrongType< T, Parameter, Skills >::StrongType ( std::enable_if_t< typename almost_self< T_ >::enable_default_constructor{}, std::nullptr_t > = nullptr)
explicitconstexpr

Default constructor, which is defined only when enable_default_constructor is defined.

This should happen only when skill DefaultConstructible is chosen.

Template Parameters
T_ArtificIal template parameter to ensure that SFINAE applies.

◆ StrongType() [4/5]

template<class T , class Parameter , template< typename > class... Skills>
MoReFEM::StrongType< T, Parameter, Skills >::StrongType ( const StrongType< T, Parameter, Skills > & rhs)
default

The copy constructor.

Parameters
[in]rhsThe object from which the construction occurs.

◆ StrongType() [5/5]

template<class T , class Parameter , template< typename > class... Skills>
MoReFEM::StrongType< T, Parameter, Skills >::StrongType ( StrongType< T, Parameter, Skills > && rhs)
default

The move constructor.

Parameters
[in]rhsThe object from which the construction occurs.

Member Function Documentation

◆ operator=() [1/2]

template<class T , class Parameter , template< typename > class... Skills>
StrongType & MoReFEM::StrongType< T, Parameter, Skills >::operator= ( const StrongType< T, Parameter, Skills > & rhs)
default

The (copy) operator=.

Parameters
[in]rhsThe object from which the affectation occurs.
Returns
Reference to the object (to enable chained affectation).

◆ operator=() [2/2]

template<class T , class Parameter , template< typename > class... Skills>
StrongType & MoReFEM::StrongType< T, Parameter, Skills >::operator= ( StrongType< T, Parameter, Skills > && rhs)
default

The (move) operator=.

Parameters
[in]rhsThe object from which the affectation occurs.
Returns
Reference to the object (to enable chained affectation).

◆ operator T()

template<class T , class Parameter , template< typename > class... Skills>
MoReFEM::StrongType< T, Parameter, Skills >::operator T ( ) const
explicitnoexcept

Conversion operator to the underlying type.

The explicit is there on purpose, please don't remove it! (otherwise the whole point of using strong types is lost...)


The documentation for this class was generated from the following file: