# std::is_convertible, std::is_nothrow_convertible

< cpp‎ | types

定义于头文件 `<type_traits>` |  |
template< class From, class To > struct is_convertible; | (1) | (C++11 起)
template< class From, class To > struct is_nothrow_convertible; | (2) | (C++20 起)

1) 若虚构函数定义 To test() { return std::declval<From>(); } 为良构，（即 std::declval<From>() 能用隐式转换转换为 `To` ，或 `From` 和 `To` 均为可有 cv 限定的 `void` ），则提供等于 true 的成员常量 `value` 。否则 `value` 为 false 。为此检查的目的，不认为 return 语句中的 std::declval 是 odr 使用。
如同从无关乎任一类型的语境中进行访问检查。仅考虑 return 语句中的表达式（包含转换到返回类型）的立即语境的合法性。
2) 同 (1) ，但转换亦为 `noexcept` 。

`From` 与 `To` 应均为完整类型、（可为 cv 限定的） void ，或未知边界数组。否则行为未定义。

若上述模板的实例化直接或间接地依赖于不完整类型，并且如果假如使该类型完整，实例化就会产生不同的结果，则行为未定义。

添加此页面上描述的任何模板的特化的程序行为未定义。

### 辅助变量模板

template< class From, class To > inline constexpr bool is_convertible_v = is_convertible<From, To>::value; |  | (C++17 起)
template< class From, class To > inline constexpr bool is_nothrow_convertible_v = is_nothrow_convertible<From, To>::value; |  | (C++20 起)

## 继承自 std::integral_constant

### 成员常量

value [静态] | 若 `From` 可转换为 `To` 则为 true ，否则为 false (公开静态成员常量)

### 成员函数

operator bool | 转换对象为 bool ，返回 `value` (公开成员函数)
operator() (C++14) | 返回 `value` (公开成员函数)

### 成员类型

类型 | 定义
`value_type` | `bool`
`type` | std::integral_constant<bool, value>

### 可能的实现

版本一
    namespace detail {

    template<class T>
    auto test_returnable(int) -> decltype(
        void(static_cast<T(*)()>(nullptr)), std::true_type{}
    );
    template<class>
    auto test_returnable(...) -> std::false_type;

    template<class From, class To>
    auto test_implicitly_convertible(int) -> decltype(
        void(std::declval<void(&)(To)>()(std::declval<From>())), std::true_type{}
    );
    template<class, class>
    auto test_implicitly_convertible(...) -> std::false_type;

    } // namespace detail

    template<class From, class To>
    struct is_convertible : std::integral_constant<bool,
        (decltype(detail::test_returnable<To>(0))::value &&
         decltype(detail::test_implicitly_convertible<From, To>(0))::value) ||
        (std::is_void<From>::value && std::is_void<To>::value)
    > {};
版本二
    template<class From, class To>
    struct is_nothrow_convertible : std::conjunction<std::is_void<From>, std::is_void<To>> {};

    template<class From, class To>
        requires
            requires {
                static_cast<To(*)()>(nullptr);
                { std::declval<void(&)(To) noexcept>()(std::declval<From>()) } noexcept;
            }
    struct is_nothrow_convertible<From, To> : std::true_type {};

### 注解

对引用类型、 void 类型、数组类型和函数类型给出良好定义的结果。

当前标准未指定是否认为转换所产生的对象（结果对象或绑定到引用的临时量）的析构是转换的一部分。此为 LWG 问题 3400 。

所有已知实现都将析构当作转换的一部分，如 P0758R1 中提议。

### 示例

    #include <iostream>
    #include <type_traits>

    class E { public: template<class T> E(T&&) { } };

    int main()
    {
        class A {};
        class B : public A {};
        class C {};
        class D { public: operator C() { return c; }  C c; };

        bool b2a = std::is_convertible<B*, A*>::value;
        bool a2b = std::is_convertible<A*, B*>::value;
        bool b2c = std::is_convertible<B*, C*>::value;
        bool d2c = std::is_convertible<D, C>::value;

        // 完美转发构造函数使类能从任何类型转换

        bool everything2e = std::is_convertible<A, E>::value; //< B, C, D 等

        std::cout << std::boolalpha;

        std::cout << b2a << '\n';
        std::cout << a2b << '\n';
        std::cout << b2c << '\n';
        std::cout << d2c << '\n';
        std::cout << '\n';
        std::cout << everything2e << '\n';
    }

输出：

    true
    false
    false
    true

    true

### 参阅