c++boosttype-traits

Is is possible to implement is_nothrow_assignable without compiler builtins?


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?


Solution

  • The is_nothrow_assignable type trait is true if both the following conditions are satisfied:

    1. the type U is assignable to the type T;
    2. the above operation is non-throwing.

    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;