Revision c5c95daaed29f72a298262ffc62e7fbca28c56f3 authored by Dmitry Yu. Naumov on 04 May 2023, 11:49:45 UTC, committed by Dmitry Yu. Naumov on 04 May 2023, 11:49:45 UTC
[MeL/IO] Increase time value output precision

Closes #3404

See merge request ogs/ogs!4582
2 parent s f5c0a8b + 4415377
Raw File
StrongType.h
/**
 * \file
 * \copyright
 * Copyright (c) 2012-2023, OpenGeoSys Community (http://www.opengeosys.org)
 *            Distributed under a Modified BSD License.
 *              See accompanying file LICENSE.txt or
 *              http://www.opengeosys.org/project/license
 *
 */

#pragma once

#include <utility>

namespace BaseLib
{
//! A "strong" version of the underlying type T.
//!
//! Strong types with same T but different tag are not implicitly convertible to
//! each other, and are not implicitly convertible to/from T. Based on these
//! properties strong types can serve as an ingredient for safer APIs.
template <typename T, typename Tag>
struct StrongType
{
    static_assert(
        !std::is_reference_v<T>,
        "The underlying type must not be a reference. This struct is not "
        "designed for references. If its design should be extended to also "
        "cover references make sure to unit test it throroughly. In this case "
        "also consider the implications for the overall usage of StrongType in "
        "the code, e.g., StrongType<int, struct Tag> and StrongType<int&, "
        "struct Tag> are not related to each other by any inheritance "
        "relation, but are completely different types, and in particular "
        "cannot be passed to functions expecting a value/reference of the "
        "other type. Therefore, allowing references as underlying types might "
        "have adverse effect on \"large scale\" API design.");

    static_assert(
        std::default_initializable<T>,
        "The underlying type must be default initializable. This struct is "
        "designed for \"general purpose\" underlying types such as numbers or "
        "matrices, which are usually default constructible. If you need "
        "support for non-default-constuctible underlying types, make sure you "
        "test your extension of the current implementation thoroughly.");

    constexpr StrongType() noexcept(std::is_nothrow_default_constructible_v<T>)
        : value_{}  // "zero initialization"
    {
    }

    constexpr explicit StrongType(T const& value) noexcept(
        std::is_nothrow_copy_constructible_v<T>)
        : value_{value}
    {
    }

    constexpr explicit StrongType(T&& value) noexcept(
        std::is_nothrow_move_constructible_v<T>)
        : value_{std::move(value)}
    {
    }

    //! Value access. Alternative to operator*, operator() might look clearer in
    //! mathematical expressions.
    [[nodiscard]] constexpr T& operator()() noexcept { return this->value_; }
    [[nodiscard]] constexpr T const& operator()() const noexcept
    {
        return value_;
    }

    //! Value access. Alternative to operator(). Introduced for symmetry reasons
    //! as a companion to operator->.
    [[nodiscard]] constexpr T& operator*() noexcept { return this->value_; }
    [[nodiscard]] constexpr T const& operator*() const noexcept
    {
        return value_;
    }

    //! Value access.
    [[nodiscard]] constexpr T* operator->() noexcept { return &this->value_; }
    [[nodiscard]] constexpr T const* operator->() const noexcept
    {
        return &value_;
    }

private:
    T value_;
};
}  // namespace BaseLib
back to top