类型特性
类型特性定义一个编译时基于模板的结构,以查询或修改类型的属性。
试图特化定义于 <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 > | (1) | (C++17 起) |
template< class T > | (2) | (C++17 起) |
template< class T, class U > | (3) | (C++17 起) |
template< class T > | (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-seq 或 ref-qualifier 的函数类型),则提供等于 false 的成员常量 value
。否则,提供等于 std::is_swappable_with<T&, T&>::value 的成员常量 value
。
3) 同 (1) ,但已知来自 (1) 的两个表达式求值都不抛异常。
4) 同 (2) ,但使用 is_nothrow_swappable_with 。
T
与 U
应均为完整类型、(可为 cv 限定的) void ,或未知边界数组。否则行为未定义。
若上述模板的实例化直接或间接地依赖于不完整类型,并且如果假如使该类型完整,实例化就会产生不同的结果,则行为未定义。
辅助变量模板
template <class T, class U> | (C++17 起) | |
template <class T> | (C++17 起) | |
template <class T, class U> | (C++17 起) | |
template <class T> | (C++17 起) |
继承自 std::integral_constant
成员常量
value [静态] | 若T 可与U 交换则为 true ,否则为 false(公开静态成员常量) |
成员函数
operator bool | 转换对象为 bool ,返回 value (公开成员函数) |
operator() (C++14) | 返回 value (公开成员函数) |
成员类型
类型 | 定义 |
value_type | bool |
type | std::integral_constant<bool, value> |
注意
此特性不检查 swap 表达式的立即语境外的内容:若 T
或 U
的使用会触发模板特化,生成隐式定义的特定成员函数等,而它们有错误,则即使 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
-----------------------------------------------