SeqAn3 3.4.0-rc.1
The Modern C++ library for sequence analysis.
Loading...
Searching...
No Matches
seqan3::detail::strong_type< value_t, derived_t, skills_ > Class Template Reference

CRTP base class to declare a strong typedef for a regular type to avoid ambiguous parameter settings in function calls. More...

#include <seqan3/core/detail/strong_type.hpp>

+ Inheritance diagram for seqan3::detail::strong_type< value_t, derived_t, skills_ >:

Public Types

using value_type = value_t
 The underlying value type.
 

Public Member Functions

Constructor, destructor and assignment.

The standard functions are explicitly set to default.

constexpr strong_type () noexcept=default
 Defaulted.
 
constexpr strong_type (strong_type const &) noexcept=default
 Defaulted.
 
constexpr strong_type (strong_type &&) noexcept=default
 Defaulted.
 
constexpr strong_typeoperator= (strong_type const &) noexcept=default
 Defaulted.
 
constexpr strong_typeoperator= (strong_type &&) noexcept=default
 Defaulted.
 
 ~strong_type () noexcept=default
 Defaulted.
 
constexpr strong_type (value_t _value)
 Construction from underlying value type.
 
Accessor.
constexpr value_t & get () &noexcept
 Returns the underlying value.
 
constexpr value_t const & get () const &noexcept
 Returns the underlying value.
 
constexpr value_t && get () &&noexcept
 Returns the underlying value as rvalue.
 
constexpr value_t const && get () const &&noexcept
 Returns the underlying value as rvalue.
 
Arithmetic additive operators.

Only available if the corresponding skills from seqan3::detail::strong_type_skill are added and the underlying type supports this operation.

constexpr derived_t operator+ (strong_type const &other)
 Adds addition operator to the strong type.
 
constexpr derived_t operator- (strong_type const &other)
 Adds subtraction operator to the strong type.
 
Arithmetic multiplicative operators.

Only available if the corresponding skills from seqan3::detail::strong_type_skill are added and the underlying type supports this operation.

constexpr derived_t operator* (strong_type const &other)
 Adds multiplication operator to the strong type.
 
constexpr derived_t operator/ (strong_type const &other)
 Adds division operator to the strong type.
 
constexpr derived_t operator% (strong_type const &other)
 Adds modulo operator to the strong type.
 
Bitwise logic operators.

Only available if the corresponding skills from seqan3::detail::strong_type_skill are added and the underlying type supports this operation.

constexpr derived_t operator& (strong_type const &other)
 Adds bitwise and operator to the strong type.
 
constexpr derived_t operator| (strong_type const &other)
 Adds bitwise or operator to the strong type.
 
constexpr derived_t operator^ (strong_type const &other)
 Adds bitwise xor operator to the strong type.
 
constexpr derived_t operator~ ()
 Adds bitwise not operator to the strong type.
 
Bitwise shift operators.

Only available if the corresponding skills from seqan3::detail::strong_type_skill are added and the underlying type supports this operation.

constexpr derived_t operator<< (strong_type const &other)
 Adds bitwise left shift operator to the strong type.
 
template<std::integral integral_t>
requires ((skills & strong_type_skill::bitwise_lshift) != strong_type_skill::none)
constexpr derived_t operator<< (integral_t const shift)
 Adds bitwise left shift operator to the strong type.
 
constexpr derived_t operator>> (strong_type const &other)
 Adds bitwise right shift operator to the strong type.
 
template<std::integral integral_t>
requires ((skills & strong_type_skill::bitwise_rshift) != strong_type_skill::none)
constexpr derived_t operator>> (integral_t const shift)
 Adds bitwise right shift operator to the strong type.
 
Logical operators.

Only available if the corresponding skills from seqan3::detail::strong_type_skill are added and the underlying type supports this operation.

constexpr bool operator&& (strong_type const &other)
 Adds logical and operator to the strong type.
 
constexpr bool operator|| (strong_type const &other)
 Adds logical or operator to the strong type.
 
constexpr bool operator! ()
 Adds logical not operator to the strong type.
 
Increment and decrement operators.

Only available if the corresponding skills from seqan3::detail::strong_type_skill are added and the underlying type supports this operation.

constexpr derived_t & operator++ ()
 Adds pre-increment operator to the strong type.
 
constexpr derived_t operator++ (int)
 Adds post-increment operator to the strong type.
 
constexpr derived_t & operator-- ()
 Adds pre-decrement operator to the strong type.
 
constexpr derived_t operator-- (int)
 Adds post-decrement operator to the strong type.
 
Comparison operators

Only available if the corresponding skill from seqan3::detail::strong_type_skill is added.

Implemented as member functions because requires does not work on friends.

constexpr bool operator== (strong_type const &rhs) const
 Return whether this instance is equal to rhs.
 
constexpr bool operator!= (strong_type const &rhs) const
 Return whether this instance is not equal to rhs.
 
Conversion operators.

Only available if the corresponding skill from seqan3::detail::strong_type_skill is added.

constexpr operator value_t () const
 Adds explicit conversion to it's underlying type.
 

Static Public Attributes

static constexpr strong_type_skill skills = skills_
 The selected skills for this type.
 

Private Attributes

value_t value
 The underlying value, which is wrapped as a strong type.
 

Related Symbols

(Note that these are not member symbols.)

Formatted output
template<typename char_t , derived_from_strong_type strong_type_t>
debug_stream_type< char_t > & operator<< (debug_stream_type< char_t > &stream, strong_type_t &&value)
 Formatted output to a seqan3::detail::debug_stream_type.
 

Detailed Description

template<typename value_t, typename derived_t, strong_type_skill skills_ = strong_type_skill::none>
class seqan3::detail::strong_type< value_t, derived_t, skills_ >

CRTP base class to declare a strong typedef for a regular type to avoid ambiguous parameter settings in function calls.

Template Parameters
value_tThe underlying type to create a strong typedef for.
derived_tThe derived class inheriting from this base class.
skills_A set of skills to be added to the expressive type.

There are many cases in which interfaces use ambiguous parameters that can be mixed up very easily. For example, if we consider an interface that expects a window size and a number of maximal errors to search for possible hits in a region of interest, both values might be given in the form of an unsigned integer. The following snippet shows a typical interface:

// SPDX-FileCopyrightText: 2006-2024 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2024 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <ranges>
#include <vector>
namespace detail
{
template <std::ranges::forward_range fwd_rng_type>
bool do_find(fwd_rng_type const &, uint8_t const, uint8_t const)
{
return true;
}
} // namespace detail
template <std::ranges::forward_range fwd_rng_type>
bool search(fwd_rng_type const & rng, uint8_t const window_size, uint8_t const error)
{
return detail::do_find(rng, window_size, error);
}
int main()
{
using namespace seqan3::literals;
std::vector<seqan3::dna4> range = "ACGTT"_dna4;
search(range, 4u, 2u);
return 0;
}
Provides seqan3::dna4, container aliases and string literals.
The SeqAn namespace for literals.
strong_type for the window_size.
Definition minimiser_hash.hpp:29

The second parameter is the window size and the third parameter represents the error threshold. But what happens if the user accidentally confuses window_size with error? In a bigger code base, this mistake can be so subtle that it becomes hard to figure out that the search interface was used in a wrong way. Also, the compiler cannot detect this. In order to make this interface safe, we have to use a strong type. A strong type is expressive in what it actually represents as a value. In our toy example, we can define two strong types as follows:

// SPDX-FileCopyrightText: 2006-2024 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2024 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
struct error : seqan3::detail::strong_type<uint8_t, error>
{
using seqan3::detail::strong_type<uint8_t, error>::strong_type;
};
struct window_size : seqan3::detail::strong_type<uint8_t, window_size>
{
using seqan3::detail::strong_type<uint8_t, window_size>::strong_type;
};
CRTP base class to declare a strong typedef for a regular type to avoid ambiguous parameter settings ...
Definition strong_type.hpp:174
Provides basic data structure for strong types.

We can now change our interface to:

// SPDX-FileCopyrightText: 2006-2024 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2024 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <ranges>
#include <vector>
struct error : seqan3::detail::strong_type<unsigned, error>
{
using seqan3::detail::strong_type<unsigned, error>::strong_type;
};
struct window_size : seqan3::detail::strong_type<unsigned, window_size>
{
using seqan3::detail::strong_type<unsigned, window_size>::strong_type;
};
namespace detail
{
template <std::ranges::forward_range fwd_rng_type>
bool do_find(fwd_rng_type const &, uint8_t const, uint8_t const)
{
return true;
}
} // namespace detail
template <std::ranges::forward_range fwd_rng_type>
bool search(fwd_rng_type const & rng, window_size const window_size, error const error)
{
return detail::do_find(rng, window_size.get(), error.get());
}
int main()
{
using namespace seqan3::literals;
std::vector<seqan3::dna4> range = "ACGTT"_dna4;
search(range, window_size{4u}, error{2u});
return 0;
}
constexpr value_t & get() &noexcept
Returns the underlying value.
Definition strong_type.hpp:201
T search(T... args)

Now the user is forced to pass the parameters as their named type. If the parameter order is mixed up, the compiler will emit an error message since the error type is not convertible to the window_size type and vice versa.

Adding Skills

In most cases, it is sufficient to protect the user interface from misuse by using strong types. Within the implementation, the underlying value can then be extracted using the seqan3::detail::strong_type::get member functions. However, there might be scenarios where the strong type is exposed to the user to work with, but with a restricted set of operations that can be applied to the type. A familiar use case are the time typedefs of the std::chrono library. It is convenient for the user to subtract two time values representing, for example, seconds, to get the duration between two time points. But not all operations like modulo or multiplication are really useful for this. In order to add skills to the seqan3::detail::strong_type, the typedef can be further specialized with operations from the seqan3::detail::strong_type_skill enum. For example, we can further augment our error type to support increment and decrement operations:

// SPDX-FileCopyrightText: 2006-2024 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2024 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
using seqan3::operator|;
struct error :
error,
seqan3::detail::strong_type_skill::decrement
| seqan3::detail::strong_type_skill::increment>
{
error,
seqan3::detail::strong_type_skill::decrement
| seqan3::detail::strong_type_skill::increment>::strong_type;
};
int main()
{
error e{4u};
--e;
++e;
}

Friends And Related Symbol Documentation

◆ operator<<()

template<typename char_t , derived_from_strong_type strong_type_t>
debug_stream_type< char_t > & operator<< ( debug_stream_type< char_t > &  stream,
strong_type_t &&  value 
)
related

Formatted output to a seqan3::detail::debug_stream_type.

Template Parameters
char_tThe char type of the seqan3::detail::debug_stream_type.
strong_type_tThe strong type to print; must model seqan3::detail::derived_from_strong_type.
Parameters
[in,out]streamThe output stream.
[in]valueThe strong typed value to print.

Prints the stored value of the given strong type.

Returns
stream_t & A reference to the given stream.

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