类型特性
类型特性定义一个编译时基于模板的结构,以查询或修改类型的属性。
试图特化定义于 <type_traits> 头文件的模板导致未定义行为,除了 std::common_type 可依照其所描述特化。
定义于<type_traits>头文件的模板可以用不完整类型实例化,除非另外有指定,尽管通常禁止以不完整类型实例化标准库模板。
类型关系
继承自 std::integral_constant
检查类型能否以给定的实参类型调用
std::is_invocable,
std::is_invocable_r,
std::is_nothrow_invocable,
std::is_nothrow_invocable_r
定义于头文件 | ||
template <class Fn, class... ArgTypes> | (1) | (C++17 起) |
template <class R, class Fn, class... ArgTypes> | (2) | (C++17 起) |
template <class Fn, class... ArgTypes> | (3) | (C++17 起) |
template <class R, class Fn, class... ArgTypes> | (4) | (C++17 起) |
1) 确定是否能以参数 ArgTypes...
调用 Fn
。正式而言,确定 INVOKE(declval<Fn>(), declval<ArgTypes>()...)
在被当做不求值运算数时是否为良式,其中 INVOKE
是 可调用 (Callable) 中定义的运算。
2) 确定是否能以参数 ArgTypes...
调用 Fn
并生成可转换为 R
的结果。正式而言,确定 INVOKE<R>(declval<Fn>(), declval<ArgTypes>()...)
在被当做不求值运算数时是否为良式,其中 INVOKE
是 可调用 (Callable) 中定义的运算。
3) 确定是否能以参数 ArgTypes...
调用 Fn
(同 (1) ),并已知这种调用不抛任何异常。
4) 确定是否能以参数 ArgTypes...
调用 Fn
并生成可转换为 R
的结果(同 (2) ),并已知这种调用(包括转换)不抛任何异常。
Fn, R
与参数包 ArgTypes
中的所有类型应均为完整类型、(可为 cv 限定的) void ,或未知边界数组。否则行为未定义。
若上述模板的实例化直接或间接地依赖于不完整类型,并且如果假如使该类型完整,实例化就会产生不同的结果,则行为未定义。
辅助变量模板
定义于头文件 | ||
template <class Fn, class... ArgTypes> | (1) | (C++17 起) |
template <class R, class Fn, class... ArgTypes> | (2) | (C++17 起) |
template <class Fn, class... ArgTypes> | (3) | (C++17 起) |
template <class R, class Fn, class... ArgTypes> | (4) | (C++17 起) |
继承自 std::integral_constant
成员常量
value [静态] | 若 INVOKE<R>(declval<Fn>(), declval<ArgTypes>()...) 在被当做不求值运算数时为良式 则为 true ,否则为 false(公开静态成员常量) |
成员函数
operator bool | 转换对象为 bool ,返回 value (公开成员函数) |
operator() (C++14) | 返回 value (公开成员函数) |
成员类型
类型 | 定义 |
value_type | bool |
type | std::integral_constant<bool, value> |
调用示例
#include <iostream>
#include <type_traits>
namespace std
{
/// std::invoke_result
template<typename _Functor, typename... _ArgTypes>
struct invoke_result
: public __invoke_result<_Functor, _ArgTypes...>
{ };
/// std::invoke_result_t
template<typename _Fn, typename... _Args>
using invoke_result_t = typename invoke_result<_Fn, _Args...>::type;
/// std::is_invocable
template<typename _Fn, typename... _ArgTypes>
struct is_invocable
: __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type
{ };
/// std::is_invocable_r
template<typename _Ret, typename _Fn, typename... _ArgTypes>
struct is_invocable_r
: __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, _Ret>::type
{ };
/// std::is_nothrow_invocable
template<typename _Fn, typename... _ArgTypes>
struct is_nothrow_invocable
: __and_<__is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>,
__call_is_nothrow_<_Fn, _ArgTypes...>>::type
{ };
template<typename _Result, typename _Ret, typename = void>
struct __is_nt_invocable_impl : false_type { };
template<typename _Result, typename _Ret>
struct __is_nt_invocable_impl<_Result, _Ret,
__void_t<typename _Result::type>>
: __or_<is_void<_Ret>,
__and_<is_convertible<typename _Result::type, _Ret>,
is_nothrow_constructible<_Ret, typename _Result::type>>>
{ };
/// std::is_nothrow_invocable_r
template<typename _Ret, typename _Fn, typename... _ArgTypes>
struct is_nothrow_invocable_r
: __and_<__is_nt_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, _Ret>,
__call_is_nothrow_<_Fn, _ArgTypes...>>::type
{ };
/// std::is_invocable_v
template<typename _Fn, typename... _Args>
inline constexpr bool is_invocable_v = is_invocable<_Fn, _Args...>::value;
/// std::is_nothrow_invocable_v
template<typename _Fn, typename... _Args>
inline constexpr bool is_nothrow_invocable_v
= is_nothrow_invocable<_Fn, _Args...>::value;
/// std::is_invocable_r_v
template<typename _Fn, typename... _Args>
inline constexpr bool is_invocable_r_v
= is_invocable_r<_Fn, _Args...>::value;
/// std::is_nothrow_invocable_r_v
template<typename _Fn, typename... _Args>
inline constexpr bool is_nothrow_invocable_r_v
= is_nothrow_invocable_r<_Fn, _Args...>::value;
}
void func() {}
struct Callable
{
void operator()() {}
};
auto func2(char) -> int (*)()
{
return nullptr;
}
int main()
{
// 检查函数指针是否可调用
std::cout << std::boolalpha;
std::cout << "std::is_invocable<decltype(func), void()>::value: "
<< std::is_invocable<decltype(func), void()>::value << std::endl;
// 检查可调用对象是否可调用
std::cout << "std::is_invocable<Callable, void()>::value: "
<< std::is_invocable<Callable, void()>::value << std::endl;
std::cout << "std::is_invocable<int()>::value: "
<< std::is_invocable<int()>::value << std::endl;
std::cout << "std::is_invocable<int, int()>::value: "
<< std::is_invocable<int, int()>::value << std::endl;
std::cout << "std::is_invocable<int(), int>::value: "
<< std::is_invocable<int(), int>::value << std::endl;
std::cout << "std::is_invocable<void, void(int), int>::value "
<< std::is_invocable<void, void(int), int>::value << std::endl;
std::cout << "std::is_invocable<int(*)(), decltype(func2), char>::value "
<< std::is_invocable<int(*)(), decltype(func2), char>::value << std::endl;
std::cout << "-----------------------------------------------" << std::endl;
std::cout << std::endl;
std::cout << "std::is_invocable_r<decltype(func), void()>::value: "
<< std::is_invocable_r<decltype(func), void()>::value << std::endl;
// 检查可调用对象是否可调用
std::cout << "std::is_invocable_r<Callable, void()>::value: "
<< std::is_invocable_r<Callable, void()>::value << std::endl;
std::cout << "std::is_invocable_r<int, int()>::value: "
<< std::is_invocable_r<int, int()>::value << std::endl;
std::cout << "std::is_invocable_r<int(), int>::value: "
<< std::is_invocable_r<int(), int>::value << std::endl;
std::cout << "std::is_invocable_r<void, void(int), int>::value "
<< std::is_invocable_r<void, void(int), int>::value << std::endl;
std::cout << "std::is_invocable_r<int(*)(), decltype(func2), char>::value "
<< std::is_invocable_r<int(*)(), decltype(func2), char>::value << std::endl;
std::cout << "-----------------------------------------------" << std::endl;
std::cout << std::endl;
std::cout << "std::is_nothrow_invocable<decltype(func), void()>::value: "
<< std::is_nothrow_invocable<decltype(func), void()>::value << std::endl;
// 检查可调用对象是否可调用
std::cout << "std::is_nothrow_invocable<Callable, void()>::value: "
<< std::is_nothrow_invocable<Callable, void()>::value << std::endl;
std::cout << "std::is_nothrow_invocable<int()>::value: "
<< std::is_nothrow_invocable<int()>::value << std::endl;
std::cout << "std::is_nothrow_invocable<int, int()>::value: "
<< std::is_nothrow_invocable<int, int()>::value << std::endl;
std::cout << "std::is_nothrow_invocable<int(), int>::value: "
<< std::is_nothrow_invocable<int(), int>::value << std::endl;
std::cout << "std::is_nothrow_invocable<void, void(int), int>::value "
<< std::is_nothrow_invocable<void, void(int), int>::value << std::endl;
std::cout << "std::is_nothrow_invocable<int(*)(), decltype(func2), char>::value "
<< std::is_nothrow_invocable<int(*)(), decltype(func2), char>::value << std::endl;
std::cout << "-----------------------------------------------" << std::endl;
std::cout << std::endl;
std::cout << "std::is_nothrow_invocable_r<decltype(func), void()>::value: "
<< std::is_nothrow_invocable_r<decltype(func), void()>::value << std::endl;
// 检查可调用对象是否可调用
std::cout << "std::is_nothrow_invocable_r<Callable, void()>::value: "
<< std::is_nothrow_invocable_r<Callable, void()>::value << std::endl;
std::cout << "std::is_nothrow_invocable_r<int, int()>::value: "
<< std::is_nothrow_invocable_r<int, int()>::value << std::endl;
std::cout << "std::is_nothrow_invocable_r<int(), int>::value: "
<< std::is_nothrow_invocable_r<int(), int>::value << std::endl;
std::cout << "std::is_nothrow_invocable_r<void, void(int), int>::value "
<< std::is_nothrow_invocable_r<void, void(int), int>::value << std::endl;
std::cout << "std::is_nothrow_invocable_r<int(*)(), decltype(func2), char>::value "
<< std::is_nothrow_invocable_r<int(*)(), decltype(func2), char>::value << std::endl;
return 0;
}
输出
std::is_invocable<decltype(func), void()>::value: false
std::is_invocable<Callable, void()>::value: false
std::is_invocable<int()>::value: true
std::is_invocable<int, int()>::value: false
std::is_invocable<int(), int>::value: false
std::is_invocable<void, void(int), int>::value false
std::is_invocable<int(*)(), decltype(func2), char>::value false
-----------------------------------------------
std::is_invocable_r<decltype(func), void()>::value: false
std::is_invocable_r<Callable, void()>::value: false
std::is_invocable_r<int, int()>::value: true
std::is_invocable_r<int(), int>::value: false
std::is_invocable_r<void, void(int), int>::value true
std::is_invocable_r<int(*)(), decltype(func2), char>::value true
-----------------------------------------------
std::is_nothrow_invocable<decltype(func), void()>::value: false
std::is_nothrow_invocable<Callable, void()>::value: false
std::is_nothrow_invocable<int()>::value: false
std::is_nothrow_invocable<int, int()>::value: false
std::is_nothrow_invocable<int(), int>::value: false
std::is_nothrow_invocable<void, void(int), int>::value false
std::is_nothrow_invocable<int(*)(), decltype(func2), char>::value false
-----------------------------------------------
std::is_nothrow_invocable_r<decltype(func), void()>::value: false
std::is_nothrow_invocable_r<Callable, void()>::value: false
std::is_nothrow_invocable_r<int, int()>::value: false
std::is_nothrow_invocable_r<int(), int>::value: false
std::is_nothrow_invocable_r<void, void(int), int>::value false
std::is_nothrow_invocable_r<int(*)(), decltype(func2), char>::value false