The context is a library to represent numbers (in this case integers) by wheighted position by radix powers for every radix R, passed as template argument. These derived types are digits of radix R, R_alphabet = {0,1,2,...,R-1}. The base class is to have holded the dig_t object as base_dig_t plus the radiz in the container for the number.
template<std::unsigned_integral Type>
struct base_dig_t;
template< std::unsigned_integral Type,
Type R
>
// It does not add any data member to class
struct dig_t : public base_dig_t<Type>;
template<std::unsigned_integral Type>
struct base_dig_t
{
// default constructor
constexpr
base_dig_t()
noexcept :
m_d(0)
{}
// constructor by constant reference to
// wrapped arithmetic integral type
constexpr
base_dig_t(const Type& t)
noexcept :
m_d(t)
{}
// constructor by move the
// wrapped arithmetic integral type
constexpr
base_dig_t(Type&& t)
noexcept :
m_d(std::move(t))
{}
// constructor by constant reference
// to derived type
template<Type R>
constexpr
base_dig_t(const dig_t<Type,R>& t)
noexcept :
m_d(t.base_dig_t::m_d)
{}
// constructor by move the derived type
template<Type R>
constexpr
base_dig_t(dig_t<Type,R>&& t)
noexcept :
m_d(std::move(t.base_dig_t::m_d))
{}
// usual constructor by reference
constexpr
base_dig_t(const base_dig_t&)
noexcept = default;
// usual constructor by move
constexpr
base_dig_t(const base_dig_t&&)
noexcept = default;
// assignation operator by constant reference
// to wrapped arithmetic integral type
constexpr
const base_dig_t &
operator= (const Type& t)
noexcept
{m_d = t;
return (*this);}
// assignation operator by reference
// to wrapped arithmetic integral type
constexpr
base_dig_t &
operator= (Type& t)
noexcept
{m_d = t;
return (*this);}
// assignation operator by move
// wrapped arithmetic integral type
constexpr
base_dig_t &
operator= (Type&& t)
noexcept
{m_d = std::move(t);
return (*this);}
// assignation operator by constant reference
// to derived type
template<Type R>
constexpr
const base_dig_t &
operator= (const dig_t<Type,R>& t)
noexcept
{m_d = t.base_dig_t::m_d;
return (*this);}
// assignation operator by reference to derived type
template<Type R>
constexpr
base_dig_t &
operator =(dig_t<Type,R>& t)
noexcept
{m_d = t.base_dig_t::m_d;
return (*this);}
// assignation operator by move the derived type
template<Type R>
constexpr
base_dig_t &
operator =(dig_t<Type,R>&& t)
noexcept
{m_d = std::move(t.base_dig_t::m_d);
return (*this);}
// usual assignation operator by constant reference
constexpr
const base_dig_t &
operator= (const base_dig_t& d)
noexcept
{m_d = d.m_d;
return (*this);}
// usual assignation operator by reference
constexpr
base_dig_t &
operator=(base_dig_t&)
noexcept = default;
// usual assignation operator by move
constexpr
base_dig_t &
operator= (base_dig_t&&)
noexcept = default;
// several casts
constexpr explicit
operator Type() const
noexcept
{return m_d;}
constexpr explicit
operator const Type&() const
noexcept
{return m_d;}
constexpr explicit
operator Type&()
noexcept
{return m_d;}
constexpr explicit
operator Type&&()
noexcept
{return std::move(m_d);}
protected:
Type m_d;
};
// This template typename does not add
// any data member to base class
template< std::unsigned_integral Type,
Type R
>
struct dig_t : public base_dig_t<Type>
{
// Contructors from base_dig_t<Type>
// Assignation operators for base_dig_t<Type>
// this->base_dig_t::m_d = arg.base_dig_t::m_d%R;
// Contructors from Type
// Assignation operators for Type
// this->base_dig_t::m_d = arg%R;
// Proper constructors
// Proper assignation operators
// Explicit overload cast operators
// to return base_dig_t::m_d
// Overload
// by template members functions
// the arithmetic operators for
// R-modular behavior
};