1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
|
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
#ifndef DUNE_COMMON_STD_TYPE_TRAITS_HH
#define DUNE_COMMON_STD_TYPE_TRAITS_HH
#include <type_traits>
#include <dune-common-config.hh> // DUNE_HAVE_CXX_EXPERIMENTAL_IS_DETECTED
#include <dune/common/typetraits.hh>
#include <dune/common/typeutilities.hh>
#if DUNE_HAVE_CXX_EXPERIMENTAL_IS_DETECTED
#include <experimental/type_traits>
#endif
namespace Dune
{
//! Namespace for features backported from new C++ standards
/**
* The namespace Dune::Std contains library features of new C++ standards and
* technical specifications backported to older compilers. Most features are
* detected and pulled into this namespace from the standard library if your
* compiler has native support. If it doesn't, we provide a fallback implementation
* on a best-effort basis.
*
* \ingroup CxxUtilities
*/
namespace Std
{
#if DUNE_HAVE_CXX_EXPERIMENTAL_IS_DETECTED
using std::experimental::nonesuch;
using std::experimental::detected_or;
using std::experimental::is_detected;
using std::experimental::detected_t;
using std::experimental::is_detected_v;
using std::experimental::detected_or_t;
using std::experimental::is_detected_exact;
using std::experimental::is_detected_exact_v;
using std::experimental::is_detected_convertible;
using std::experimental::is_detected_convertible_v;
#else // DUNE_HAVE_CXX_EXPERIMENTAL_IS_DETECTED
// fallback version of std::experimental::is_detected et al., heavily scribbled
// from cppreference.com (but there is actually not much implementation to the thing)
#ifndef DOXYGEN
namespace Impl {
// default version of detector, this gets matched on failure
template<typename Default, typename Void, template<typename...> class Op, typename... Args>
struct detector
{
using value_t = std::false_type;
using type = Default;
};
// specialization of detector that matches if Op<Args...> can be instantiated
template<typename Default, template<typename...> class Op, typename... Args>
struct detector<Default, std::void_t<Op<Args...>>, Op, Args...>
{
using value_t = std::true_type;
using type = Op<Args...>;
};
}
#endif // DOXYGEN
//! Type representing a lookup failure by std::detected_or and friends.
/**
* This type cannot be constructed, destroyed or copied.
*
* \note This functionality is part of the C++ library fundamentals TS v3 and might
* or might not became part of C++2c / C++26.
*
* \ingroup CxxUtilities
*/
struct nonesuch
{
nonesuch() = delete;
~nonesuch() = delete;
nonesuch(const nonesuch&) = delete;
void operator=(const nonesuch&) = delete;
};
//! Detects whether `Op<Args...>` is valid and makes the result available.
/**
* This alias template is an alias for an unspecified class type with two
* nested `typedefs` `value_t` and `type`. It can be used to detect whether
* the meta function call `Op<Args...>` is valid and access the result of
* the call by inspecting the returned type, which is defined as follows:
*
* * If `Op<Args...>` can be instantiated, `value_t` is an alias for `std::true_type`
* and `type` is an alias for `Op<Args...>`.
* * If `Op<Args...>` is invalid, `value_t` is an alias for `std::false_type`
* and `type` is an alias for `Default`.
*
* This can be used to safely extract a nested `typedef` from a type `T` that
* might not define the `typedef`:
\code
struct A { using size_type = int ; };
struct B;
template<typename T>
using SizeType = typename T::size_type;
// this extracts the nested typedef for int
using st_a = typename detected_or<std::size_t,SizeType,A>::type;
// as there is no nested typedef in B, this yields std::size_t
using st_b = typename detected_or<std::size_t,SizeType,B>::type;
\endcode
*
* Do not directly use the nested `typedefs` `value_t` and `type` as
* they are implementation details.
*
* \note This functionality is part of the C++ library fundamentals TS v3 and might
* or might not became part of C++2c / C++26.
*
* \ingroup CxxUtilities
*/
template<typename Default, template<typename...> class Op, typename... Args>
using detected_or = Impl::detector<Default,void,Op,Args...>;
//! Detects whether `Op<Args...>` is valid.
/**
* This alias template checks whether `Op<Args...>` can be instantiated. It is
* equivalent to `typename detected_or<nonesuch,Op,Args...>::value_t`.
*
* \note This functionality is part of the C++ library fundamentals TS v3 and might
* or might not became part of C++2c / C++26.
*
* \ingroup CxxUtilities
*/
template<template<typename...> class Op, typename... Args>
using is_detected = typename detected_or<nonesuch,Op,Args...>::value_t;
#ifdef __cpp_variable_templates
//! Detects whether `Op<Args...>` is valid and makes the result available as a value.
/**
* This constexpr variable checks whether `Op<Args...>` can be instantiated. It is
* equivalent to `is_detected<Op,Args...>::value`.
*
* \note This functionality is part of the C++ library fundamentals TS v3 and might
* or might not became part of C++2c / C++26.
*
* \ingroup CxxUtilities
*/
template<template<typename...> class Op, typename... Args>
constexpr bool is_detected_v = is_detected<Op,Args...>::value;
#endif // __cpp_variable_templates
//! Returns `Op<Args...>` if that is valid; otherwise returns nonesuch.
/**
* This alias template can be used to instantiate `Op<Args...>` in a context that is
* not SFINAE-safe by appropriately wrapping the instantiation. If instantiation fails,
* the marker type nonesuch is returned instead.
*
* \note This functionality is part of the C++ library fundamentals TS v3 and might
* or might not became part of C++2c / C++26.
*
* \ingroup CxxUtilities
*/
template<template<typename...> class Op, typename... Args>
using detected_t = typename detected_or<nonesuch,Op,Args...>::type;
//! Returns `Op<Args...>` if that is valid; otherwise returns the fallback type `Default`.
/**
* This alias template can be used to instantiate `Op<Args...>` in a context that is
* not SFINAE-safe by appropriately wrapping the instantiation and automatically falling back
* to `Default` if instantiation fails.
*
* \note This functionality is part of the C++ library fundamentals TS v3 and might
* or might not became part of C++2c / C++26.
*
* \ingroup CxxUtilities
*/
template<typename Default, template<typename...> class Op, typename... Args>
using detected_or_t = typename detected_or<Default,Op,Args...>::type;
//! Checks whether `Op<Args...>` is `Expected` without causing an error if `Op<Args...>` is invalid.
/**
* \note This functionality is part of the C++ library fundamentals TS v3 and might
* or might not became part of C++2c / C++26.
*
* \ingroup CxxUtilities
*/
template<typename Expected, template<typename...> class Op, typename... Args>
using is_detected_exact = std::is_same<Expected,detected_t<Op,Args...>>;
#ifdef __cpp_variable_templates
//! Convenient access to the result value of is_detected_exact.
/**
* \note This functionality is part of the C++ library fundamentals TS v3 and might
* or might not became part of C++2c / C++26.
*
* \ingroup CxxUtilities
*/
template<typename Expected, template<typename...> class Op, typename... Args>
constexpr bool is_detected_exact_v = is_detected_exact<Expected,Op,Args...>::value;
#endif // __cpp_variable_templates
//! Checks whether `Op<Args...>` is convertible to `Target` without causing an error if `Op<Args...>` is invalid.
/**
* \note This functionality is part of the C++ library fundamentals TS v3 and might
* or might not became part of C++2c / C++26.
*
* \ingroup CxxUtilities
*/
template<typename Target, template<typename...> class Op, typename... Args>
using is_detected_convertible = std::is_convertible<Target,detected_t<Op,Args...>>;
#ifdef __cpp_variable_templates
//! Convenient access to the result value of is_detected_convertible.
/**
* \note This functionality is part of the C++ library fundamentals TS v3 and might
* or might not became part of C++2c / C++26.
*
* \ingroup CxxUtilities
*/
template<typename Target, template<typename...> class Op, typename... Args>
constexpr bool is_detected_convertible_v = is_detected_convertible<Target,Op,Args...>::value;
#endif // __cpp_variable_templates
#endif // DUNE_HAVE_CXX_EXPERIMENTAL_IS_DETECTED
} // namespace Std
namespace detail
{
template <class Type>
[[deprecated("Type extraction of `TargetType` has failed. Inspect the code calling `detected_or_fallback_t` for getting the source of this warning!")]]
Type warningIfNotDefined(const Std::nonesuch*);
template <class Type, class T>
Type warningIfNotDefined(const T*);
}
//! This type will be either TargetType<Args...> if it exists, or the Fallback<Args...> type.
template <template<typename...> class Fallback,
template<typename...> class TargetType, typename... Args>
using detected_or_fallback_t = Std::detected_or_t<decltype(
detail::warningIfNotDefined<Std::detected_t<Fallback, Args...> >(std::declval<const Std::detected_t<TargetType, Args...>*>())),
TargetType, Args...>;
} // namespace Dune
#endif // #ifndef DUNE_COMMON_STD_TYPE_TRAITS_HH
|