src/typeconversions.h

Sat, 08 Apr 2023 12:55:11 +0300

author
Teemu Piippo <teemu.s.piippo@gmail.com>
date
Sat, 08 Apr 2023 12:55:11 +0300
changeset 343
4a82990affd5
parent 250
2837b549e616
permissions
-rw-r--r--

Fix BFC formatting not working due to being evaluated after comment format

#ifndef TYPECONVERSIONS_H
#define TYPECONVERSIONS_H
#include <type_traits>
#include <QtGlobal>

template<typename T, typename R>
struct transfer_cvref
{
	using type = std::remove_reference_t<R>;
};

template<typename T, typename R>
struct transfer_cvref<T&, R>
{
	using type = std::remove_reference_t<R>&;
};

template<typename T, typename R>
struct transfer_cvref<const T&, R>
{
	using type = const std::remove_reference_t<R>&;
};

template<typename T, typename R>
struct transfer_cvref<T&&, R>
{
	using type = std::remove_reference_t<R>&&;
};

//! \brief transfer l-value reference, r-value reference and const l-value
//! reference from T onto R
template<typename T, typename R>
using transfer_cvref_t = typename transfer_cvref<T, R>::type;
static_assert(std::is_same_v<transfer_cvref_t<int, char>, char>);
static_assert(std::is_same_v<transfer_cvref_t<int&, char>, char&>);
static_assert(std::is_same_v<transfer_cvref_t<int&&, char>, char&&>);

//! \brief casts @c x to a suitable unsigned integer
template<typename T>
constexpr auto unsigned_cast(T x)
	-> std::enable_if_t<std::is_integral_v<T>, std::make_unsigned_t<T>>
{
	return static_cast<std::make_unsigned_t<T>>(x);
}

//! \brief casts @c x to a suitable signed integer
template<typename T>
constexpr auto signed_cast(T x)
	-> std::enable_if_t<std::is_integral_v<T>, std::make_signed_t<T>>
{
	return static_cast<std::make_signed_t<T>>(x);
}

//! \brief casts floating point values to float
template<typename T>
constexpr auto float_cast(T x)
	-> std::enable_if_t<std::is_floating_point_v<T>, float>
{
	return static_cast<float>(x);
}

//! \brief casts floating point values to double
template<typename T>
constexpr auto double_cast(T x)
	-> std::enable_if_t<std::is_floating_point_v<T>, double>
{
	return static_cast<double>(x);
}

//! \brief casts floating point values to qreal
template<typename T>
constexpr auto qreal_cast(T x)
	-> std::enable_if_t<std::is_floating_point_v<T>, qreal>
{
	return static_cast<qreal>(x);
}

//! \brief convert an enum value to its corresponding integer value (including
//! references)
template<typename T>
constexpr auto&& enum_value_cast(T&& enu)
{
	using valuetype = std::underlying_type_t<std::remove_cvref_t<T>>;
	using reftype = transfer_cvref_t<T&&, valuetype>;
	return reinterpret_cast<reftype>(enu);
}

//! \brief A version of static_cast that only works if casting from a wider
//! integer type to a narrower integer type.
template<typename T, typename R>
constexpr auto narrow(R x)
-> std::enable_if_t<sizeof(T) <= sizeof(R) and std::is_signed_v<T> == std::is_signed_v<R>, T>
{
	return static_cast<T>(x);
}

template<typename T, typename R>
constexpr auto widen(R x)
-> std::enable_if_t<sizeof(T) >= sizeof(R) and std::is_signed_v<T> == std::is_signed_v<R>, T>
{
	return static_cast<T>(x);
}

#endif // TYPECONVERSIONS_H

mercurial