MSVC and LLVM use the compiler built-in functions invariably. Boost also doesn't provide any possible implementation.
If it cannot be implemented perfectly, are there any approximate implementations to fall back? For example, take advantage of or modify the literally similar std::is_assignable
and std::is_nothrow_move_assignable
provided by Boost?
The is_nothrow_assignable
type trait is true if both the following conditions are satisfied:
U
is assignable to the type T
;To implement the first one, it is sufficient to verify whether the expression std::declval<T&>() = std::declval<U>()
is well-formed.
Example:
namespace detail {
template <typename, typename, typename = void>
struct is_assignable
: std::false_type {};
template <typename T, typename U>
struct is_assignable<T, U, std::void_t<decltype(std::declval<T&>() = std::declval<U>())>>
: std::true_type {};
}
template <typename T, typename U>
struct is_assignable
: detail::is_assignable<T, U> {};
template <typename T, typename U>
inline constexpr bool is_assignable_v = is_assignable<T, U>::value;
To verify whether the expression is also non-throwing, it is sufficient to modify the above type trait to use the noexcept operator.
Example:
namespace detail {
template <typename, typename, bool = true>
struct is_nothrow_assignable
: std::false_type {};
template <typename T, typename U>
struct is_nothrow_assignable<T, U, noexcept(std::declval<T&>() = std::declval<U>())>
: std::true_type {};
}
template <typename T, typename U>
struct is_nothrow_assignable
: detail::is_nothrow_assignable<T, U> {};
template <typename T, typename U>
inline constexpr bool is_nothrow_assignable_v = is_nothrow_assignable<T, U>::value;