cast-to-const.hh 2.25 KB
Newer Older
/** Copyright (C) 2010-2024 Belledonne Communications SARL
 *  SPDX-License-Identifier: AGPL-3.0-or-later
 */

/** Safely cast wrapped types to const.
 *
 *  Using a wrapper type like std::shared_ptr<T> as if it was a std::shared_ptr<const T> is always safe, since we are
 *  restricting the set of operations that can be made on it, not broadening it.
 *  However C++'s type system does not allow for such casts.
 *
 *  You could use reinterpret_cast directly, but that would be dangerous if the underlying type is later changed. (e.g.
 *  std::map<std::shared_ptr<T>> -> std::unordered_map<std::shared_ptr<T>>).
 *  The functions in this file provide a (non-exhaustive) list of safe casts, while ensuring your code still type-checks
 *  in a sane way.
 */

#pragma once

constexpr bool is_interior_const = true;
constexpr bool
    is_interior_const<T, std::void_t<decltype(*std::declval<T>() = std::declval<decltype(*std::declval<T>())>())>> =
        false;
template <typename T>
struct add_interior_const {
	static_assert(is_interior_const<T>);
	using type = T;
};
using add_interior_const_t = typename add_interior_const<T>::type;
template <template <typename...> class Tmpl, typename... Args>
struct add_interior_const<Tmpl<Args...>> {
	static_assert(is_interior_const<Tmpl<Args...>>);
	using type = Tmpl<add_interior_const_t<Args>...>;
};
struct add_interior_const<std::unique_ptr<T>> {
	using type = std::unique_ptr<std::add_const_t<add_interior_const_t<T>>>;
};
struct add_interior_const<std::weak_ptr<T>> {
	using type = std::weak_ptr<std::add_const_t<add_interior_const_t<T>>>;
};
struct add_interior_const<std::shared_ptr<T>> {
	using type = std::shared_ptr<std::add_const_t<add_interior_const_t<T>>>;
};
template <typename T, std::size_t S>
struct add_interior_const<std::array<T, S>> {
	using type = std::array<add_interior_const_t<T>, S>;
};
template <typename T>
const add_interior_const_t<T>& castToConst(const T& t) {
	return reinterpret_cast<const add_interior_const_t<T>&>(t);