C++标准模板(STL)- 类型支持 (检查一个类型的对象是否能与同类型或不同类型的对,std::is_swappable_with, std::is_swappable)

类型特性

类型特性定义一个编译时基于模板的结构,以查询或修改类型的属性。

试图特化定义于 <type_traits> 头文件的模板导致未定义行为,除了 std::common_type 可依照其所描述特化。

定义于<type_traits>头文件的模板可以用不完整类型实例化,除非另外有指定,尽管通常禁止以不完整类型实例化标准库模板。

受支持操作

检查一个类型的对象是否能与同类型或不同类型的对

std::is_swappable_with, 
std::is_swappable, 
std::is_nothrow_swappable_with, 
std::is_nothrow_swappable

template< class T, class U >
struct is_swappable_with;

(1)(C++17 起)

template< class T >
struct is_swappable;

(2)(C++17 起)

template< class T, class U >
struct is_nothrow_swappable_with;

(3)(C++17 起)

template< class T >
struct is_nothrow_swappable;

(4)(C++17 起)

1) 若表达式 swap(std::declval<T>(), std::declval<U>()) 及 swap(std::declval<U>(), std::declval<T>()) 在使用 using std::swap; (见 可交换 (Swappable) )后的不求值语境中均为良式,则提供等于 true 的成员常量 value 。否则 value 为 false 。如同从与任一类型皆无关的语境进行访问检查。

2) 若 T 不是可解引用类型(即可为 cv 限定的 void 或拥有 cv-qualifier-seqref-qualifier 的函数类型),则提供等于 false 的成员常量 value 。否则,提供等于 std::is_swappable_with<T&, T&>::value 的成员常量 value

3) 同 (1) ,但已知来自 (1) 的两个表达式求值都不抛异常。

4) 同 (2) ,但使用 is_nothrow_swappable_with 。

TU 应均为完整类型、(可为 cv 限定的) void ,或未知边界数组。否则行为未定义。

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

辅助变量模板

template <class T, class U>
inline constexpr bool is_swappable_with_v = is_swappable_with<T, U>::value;

(C++17 起)

template <class T>
inline constexpr bool is_swappable_v = is_swappable<T>::value;

(C++17 起)

template <class T, class U>
inline constexpr bool is_nothrow_swappable_with_v = is_nothrow_swappable_with<T, U>::value;

(C++17 起)

template <class T>
inline constexpr bool is_nothrow_swappable_v = is_nothrow_swappable<T>::value;

(C++17 起)

继承自 std::integral_constant

成员常量

value

[静态]

T可与U交换则为 true ,否则为 false
(公开静态成员常量)

成员函数

operator bool

转换对象为 bool ,返回 value
(公开成员函数)

operator()

(C++14)

返回 value
(公开成员函数)

成员类型

类型定义
value_typebool
typestd::integral_constant<bool, value>

注意

此特性不检查 swap 表达式的立即语境外的内容:若 TU 的使用会触发模板特化,生成隐式定义的特定成员函数等,而它们有错误,则即使 std::is_swappable_with<T,U>::value 通过编译且求值为 true ,实际的 swap 也可能无法编译。

调用示例

#include <type_traits>
#include <utility>
#include <iostream>

namespace std
{
template <typename _Tp>
struct __is_swappable;

template <typename _Tp>
struct __is_nothrow_swappable;

template<typename... _Elements>
class tuple;

template<typename>
struct __is_tuple_like_impl : false_type
{ };

template<typename... _Tps>
struct __is_tuple_like_impl<tuple<_Tps...>> : true_type
{ };

// Internal type trait that allows us to sfinae-protect tuple_cat.
template<typename _Tp>
struct __is_tuple_like
    : public __is_tuple_like_impl<typename remove_cv<
      typename remove_reference<_Tp>::type>::type>::type
{ };

template<typename _Tp>
inline
typename enable_if<__and_<__not_<__is_tuple_like<_Tp>>,
         is_move_constructible<_Tp>,
         is_move_assignable<_Tp>>::value>::type
         swap(_Tp&, _Tp&)
         noexcept(__and_<is_nothrow_move_constructible<_Tp>,
                  is_nothrow_move_assignable<_Tp>>::value);

template<typename _Tp, size_t _Nm>
inline
typename enable_if<__is_swappable<_Tp>::value>::type
swap(_Tp(&__a)[_Nm], _Tp(&__b)[_Nm])
noexcept(__is_nothrow_swappable<_Tp>::value);

namespace __swappable_details
{
using std::swap;

struct __do_is_swappable_impl
{
    template<typename _Tp, typename
             = decltype(swap(std::declval<_Tp&>(), std::declval<_Tp&>()))>
    static true_type __test(int);

    template<typename>
    static false_type __test(...);
};

struct __do_is_nothrow_swappable_impl
{
    template<typename _Tp>
    static __bool_constant <
    noexcept(swap(std::declval<_Tp&>(), std::declval<_Tp&>()))
    > __test(int);

    template<typename>
    static false_type __test(...);
};

} // namespace __swappable_details

template<typename _Tp>
struct __is_swappable_impl
    : public __swappable_details::__do_is_swappable_impl
{
    typedef decltype(__test<_Tp>(0)) type;
};

template<typename _Tp>
struct __is_nothrow_swappable_impl
    : public __swappable_details::__do_is_nothrow_swappable_impl
{
    typedef decltype(__test<_Tp>(0)) type;
};

template<typename _Tp>
struct __is_swappable
    : public __is_swappable_impl<_Tp>::type
{ };

template<typename _Tp>
struct __is_nothrow_swappable
    : public __is_nothrow_swappable_impl<_Tp>::type
{ };

/// is_swappable
template<typename _Tp>
struct is_swappable
    : public __is_swappable_impl<_Tp>::type
{ };

/// is_nothrow_swappable
template<typename _Tp>
struct is_nothrow_swappable
    : public __is_nothrow_swappable_impl<_Tp>::type
{ };

#if __cplusplus >= 201402L
/// is_swappable_v
template<typename _Tp>
_GLIBCXX17_INLINE constexpr bool is_swappable_v =
    is_swappable<_Tp>::value;

/// is_nothrow_swappable_v
template<typename _Tp>
_GLIBCXX17_INLINE constexpr bool is_nothrow_swappable_v =
    is_nothrow_swappable<_Tp>::value;
#endif // __cplusplus >= 201402L

namespace __swappable_with_details
{
using std::swap;

struct __do_is_swappable_with_impl
{
    template<typename _Tp, typename _Up, typename
             = decltype(swap(std::declval<_Tp>(), std::declval<_Up>())),
             typename
             = decltype(swap(std::declval<_Up>(), std::declval<_Tp>()))>
    static true_type __test(int);

    template<typename, typename>
    static false_type __test(...);
};

struct __do_is_nothrow_swappable_with_impl
{
    template<typename _Tp, typename _Up>
    static __bool_constant <
    noexcept(swap(std::declval<_Tp>(), std::declval<_Up>()))
    &&
    noexcept(swap(std::declval<_Up>(), std::declval<_Tp>()))
    > __test(int);

    template<typename, typename>
    static false_type __test(...);
};

} // namespace __swappable_with_details

template<typename _Tp, typename _Up>
struct __is_swappable_with_impl
    : public __swappable_with_details::__do_is_swappable_with_impl
{
    typedef decltype(__test<_Tp, _Up>(0)) type;
};

// Optimization for the homogenous lvalue case, not required:
template<typename _Tp>
struct __is_swappable_with_impl<_Tp&, _Tp&>
    : public __swappable_details::__do_is_swappable_impl
{
    typedef decltype(__test<_Tp&>(0)) type;
};

template<typename _Tp, typename _Up>
struct __is_nothrow_swappable_with_impl
    : public __swappable_with_details::__do_is_nothrow_swappable_with_impl
{
    typedef decltype(__test<_Tp, _Up>(0)) type;
};

// Optimization for the homogenous lvalue case, not required:
template<typename _Tp>
struct __is_nothrow_swappable_with_impl<_Tp&, _Tp&>
    : public __swappable_details::__do_is_nothrow_swappable_impl
{
    typedef decltype(__test<_Tp&>(0)) type;
};

/// is_swappable_with
template<typename _Tp, typename _Up>
struct is_swappable_with
    : public __is_swappable_with_impl<_Tp, _Up>::type
{ };

/// is_nothrow_swappable_with
template<typename _Tp, typename _Up>
struct is_nothrow_swappable_with
    : public __is_nothrow_swappable_with_impl<_Tp, _Up>::type
{ };

/// is_swappable_with_v
template<typename _Tp, typename _Up>
constexpr bool is_swappable_with_v =
    is_swappable_with<_Tp, _Up>::value;

/// is_nothrow_swappable_with_v
template<typename _Tp, typename _Up>
constexpr bool is_nothrow_swappable_with_v =
    is_nothrow_swappable_with<_Tp, _Up>::value;

} // namespace std

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

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

int main()
{
    std::cout << std::boolalpha;

    std::cout << "std::is_swappable_with<B*, A*>::value:           "
              << std::is_swappable_with<B*, A*>::value << std::endl;
    std::cout << "std::is_swappable_with<A*, B*>::value:           "
              << std::is_swappable_with<A*, B*>::value << std::endl;
    std::cout << "std::is_swappable_with<B*, C*>::value:           "
              << std::is_swappable_with<B*, C*>::value << std::endl;
    std::cout << "std::is_swappable_with<D, C>::value:             "
              << std::is_swappable_with<D, C>::value << std::endl;
    std::cout << "std::is_swappable_with<E, A>::value:             "
              << std::is_swappable_with<E, A>::value << std::endl;
    std::cout << "std::is_swappable_with<int, double>::value:      "
              << std::is_swappable_with<int, double>::value << std::endl;
    std::cout << "std::is_swappable_with<int, int>::value:         "
              << std::is_swappable_with<int, int>::value << std::endl;
    std::cout << "std::is_swappable_with<int, char>::value:        "
              << std::is_swappable_with<int, char>::value << std::endl;
    std::cout << "std::is_swappable_with<std::string, char>::value:"
              << std::is_swappable_with<std::string, char>::value << std::endl;

    std::cout << "-----------------------------------------------" << std::endl;
    std::cout << std::endl;

    std::cout << "std::is_swappable<B*>::value:                     "
              << std::is_swappable<B*>::value << std::endl;
    std::cout << "std::is_swappable<A*>::value:                     "
              << std::is_swappable<A*>::value << std::endl;
    std::cout << "std::is_swappable<B*>::value:                     "
              << std::is_swappable<B*>::value << std::endl;
    std::cout << "std::is_swappable<D>::value:                      "
              << std::is_swappable<D>::value << std::endl;
    std::cout << "std::is_swappable<E>::value:                      "
              << std::is_swappable<E>::value << std::endl;
    std::cout << "std::is_swappable<int>::value:                    "
              << std::is_swappable<int>::value << std::endl;
    std::cout << "std::is_swappable<char>::value:                   "
              << std::is_swappable<char>::value << std::endl;
    std::cout << "std::is_swappable<double>::value:                 "
              << std::is_swappable<double>::value << std::endl;
    std::cout << "std::is_swappable<std::string>::value:            "
              << std::is_swappable<std::string>::value << std::endl;

    std::cout << "-----------------------------------------------" << std::endl;
    std::cout << std::endl;

    std::cout << "std::is_nothrow_swappable_with<B*, A*>::value:           "
              << std::is_nothrow_swappable_with<B*, A*>::value << std::endl;
    std::cout << "std::is_nothrow_swappable_with<A*, B*>::value:           "
              << std::is_nothrow_swappable_with<A*, B*>::value << std::endl;
    std::cout << "std::is_nothrow_swappable_with<B*, C*>::value:           "
              << std::is_nothrow_swappable_with<B*, C*>::value << std::endl;
    std::cout << "std::is_nothrow_swappable_with<D, C>::value:             "
              << std::is_nothrow_swappable_with<D, C>::value << std::endl;
    std::cout << "std::is_nothrow_swappable_with<E, A>::value:             "
              << std::is_nothrow_swappable_with<E, A>::value << std::endl;
    std::cout << "std::is_nothrow_swappable_with<int, double>::value:      "
              << std::is_nothrow_swappable_with<int, double>::value << std::endl;
    std::cout << "std::is_nothrow_swappable_with<int, int>::value:         "
              << std::is_nothrow_swappable_with<int, int>::value << std::endl;
    std::cout << "std::is_nothrow_swappable_with<int, char>::value:        "
              << std::is_nothrow_swappable_with<int, char>::value << std::endl;
    std::cout << "std::is_nothrow_swappable_with<std::string, char>::value:"
              << std::is_nothrow_swappable_with<std::string, char>::value << std::endl;

    std::cout << "-----------------------------------------------" << std::endl;
    std::cout << std::endl;

    std::cout << "std::is_nothrow_swappable<B*>::value:                     "
              << std::is_nothrow_swappable<B*>::value << std::endl;
    std::cout << "std::is_nothrow_swappable<A*>::value:                     "
              << std::is_nothrow_swappable<A*>::value << std::endl;
    std::cout << "std::is_nothrow_swappable<B*>::value:                     "
              << std::is_nothrow_swappable<B*>::value << std::endl;
    std::cout << "std::is_nothrow_swappable<D>::value:                      "
              << std::is_nothrow_swappable<D>::value << std::endl;
    std::cout << "std::is_nothrow_swappable<E>::value:                      "
              << std::is_nothrow_swappable<E>::value << std::endl;
    std::cout << "std::is_nothrow_swappable<int>::value:                    "
              << std::is_nothrow_swappable<int>::value << std::endl;
    std::cout << "std::is_nothrow_swappable<char>::value:                   "
              << std::is_nothrow_swappable<char>::value << std::endl;
    std::cout << "std::is_nothrow_swappable<double>::value:                 "
              << std::is_nothrow_swappable<double>::value << std::endl;
    std::cout << "std::is_nothrow_swappable<std::string>::value:            "
              << std::is_nothrow_swappable<std::string>::value << std::endl;

    std::cout << "-----------------------------------------------" << std::endl;
    std::cout << std::endl;
    return 0;
}

输出

std::is_swappable_with<B*, A*>::value:           false
std::is_swappable_with<A*, B*>::value:           false
std::is_swappable_with<B*, C*>::value:           false
std::is_swappable_with<D, C>::value:             false
std::is_swappable_with<E, A>::value:             false
std::is_swappable_with<int, double>::value:      false
std::is_swappable_with<int, int>::value:         false
std::is_swappable_with<int, char>::value:        false
std::is_swappable_with<std::string, char>::value:false
-----------------------------------------------

std::is_swappable<B*>::value:                     false
std::is_swappable<A*>::value:                     false
std::is_swappable<B*>::value:                     false
std::is_swappable<D>::value:                      false
std::is_swappable<E>::value:                      false
std::is_swappable<int>::value:                    false
std::is_swappable<char>::value:                   false
std::is_swappable<double>::value:                 false
std::is_swappable<std::string>::value:            true
-----------------------------------------------

std::is_nothrow_swappable_with<B*, A*>::value:           false
std::is_nothrow_swappable_with<A*, B*>::value:           false
std::is_nothrow_swappable_with<B*, C*>::value:           false
std::is_nothrow_swappable_with<D, C>::value:             false
std::is_nothrow_swappable_with<E, A>::value:             false
std::is_nothrow_swappable_with<int, double>::value:      false
std::is_nothrow_swappable_with<int, int>::value:         false
std::is_nothrow_swappable_with<int, char>::value:        false
std::is_nothrow_swappable_with<std::string, char>::value:false
-----------------------------------------------

std::is_nothrow_swappable<B*>::value:                     false
std::is_nothrow_swappable<A*>::value:                     false
std::is_nothrow_swappable<B*>::value:                     false
std::is_nothrow_swappable<D>::value:                      false
std::is_nothrow_swappable<E>::value:                      false
std::is_nothrow_swappable<int>::value:                    false
std::is_nothrow_swappable<char>::value:                   false
std::is_nothrow_swappable<double>::value:                 false
std::is_nothrow_swappable<std::string>::value:            false
-----------------------------------------------

  • 24
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值