C++ 具名要求-全库范围的概念 - 能以函数调用语法进行调用的对象(FunctionObject)- 定义了调用操作的类型(Callable)
此页面中列出的具名要求,是 C++ 标准的规范性文本中使用的具名要求,用于定义标准库的期待。
某些具名要求在 C++20 中正在以概念语言特性进行形式化。在那之前,确保以满足这些要求的模板实参实例化标准库模板是程序员的重担。若不这么做,则可能导致非常复杂的编译器诊断。
全库范围的概念
 能以函数调用语法进行调用的对象
 
C++ 具名要求: FunctionObject函数对象 (FunctionObject) 类型是可用在函数调用运算符左侧的对象的类型。
要求
若满足下列条件,则类型 T 满足 FunctionObject
- 类型 T满足 std::is_object,且
给定
- T或- const T类型的值- f
- args,为适合的实参列表,可以为空
则下列表达式必须合法:
| 表达式 | 要求 | 
|---|---|
| f(args) | 进行函数调用 | 
注解
函数和到函数的引用不是函数对象类型,但因为函数到指针隐式转换,它们能用在期待函数对象类型的地方。
标准库
- 所有函数指针都满足此要求。
- 所有定义于 <functional> 的函数对象。
- 某些 <functional> 的函数的返回类型。
定义了调用操作的类型
C++ 具名要求: Callable可调用 (Callable) 类型是可应用 INVOKE 操作(例如用于 std::function、std::bind 和 std::thread::thread)的类型。此操作可以用库函数 std::invoke 显式进行。 (C++17 起)
要求
若满足下列条件,则类型 T 满足可调用 (Callable)
给定
- T类型的对象- f
- 适合的实参类型列表 ArgTypes
- 适合的返回类型 R
则下列表达式必须合法:
| 表达式 | 要求 | 
|---|---|
| INVOKE<R>(f, std::declval<ArgTypes>()...) | 该表达式在不求值语境中良构 | 
其中 INVOKE<R>(f, t1, t2, ..., tN),若 R 是可有 cv 限定的 void,则定义为 static_cast<void>(INVOKE(f, t1, t2, ..., tN)),否则为 INVOKE(f, t1, t2, ..., tN),隐式转换成 R
其中 INVOKE(f, t1, t2, ..., tN) 定义如下:
- 若 f是类T的成员函数指针:
- 若 std::is_base_of<T, std::remove_reference_t<decltype(t1)>>::value 为 true,则 INVOKE(f, t1, t2, ..., tN) 等价于 (t1.*f)(t2, ..., tN)
- 否则,若 std::remove_cvref_t<decltype(t1)> 为 std::reference_wrapper 的特化,则 INVOKE(f, t1, t2, ..., tN) 等价于 (t1.get().*f)(t2, ..., tN) (C++17 起)
- 否则,若 t1不满足前述条件,则 INVOKE(f, t1, t2, ..., tN) 等价于 ((*t1).*f)(t2, ..., tN)。
- 否则,若 N == 1 且 f是类T的数据成员指针:
- 若 std::is_base_of<T, std::remove_reference_t<decltype(t1)>>::value 为 true,则 INVOKE(f, t1) 等价于 t1.*f
- 否则,若 std::remove_cvref_t<decltype(t1)> 是 std::reference_wrapper 的特化,则 INVOKE(f, t1) 等价于 t1.get().*f (C++17 起)
- 否则,若 t1不满足前述条件,则 INVOKE(f, t1) 等价于 (*t1).*f
- 否则,INVOKE(f, t1, t2, ..., tN) 等价于 f(t1, t2, ..., tN)(即 f是一个函数对象 (FunctionObject) )
注解
对于成员函数指针和数据成员指针,t1 可以是一个常规指针或一个重载了 operator* 的类的对象,例如 std::unique_ptr 或 std::shared_ptr。
数据成员指针为可调用 (Callable) ,尽管并不发生函数调用。
标准库
此外,下列标准库设施接受任何可调用 (Callable) 类型(不仅是函数对象 (FunctionObject) )
| std::function | |
| std::bind | |
| std::result_of | |
| std::thread::thread | |
| std::call_once | |
| std::async | |
| std::packaged_task | |
| std::reference_wrapper | 
调用示例
#include <iostream>
#include <functional>
#include <thread>
#include <mutex>
#include <future>
int main()
{
    std::cout << std::boolalpha;
    //匿名函数
    auto function1 = [](int a)
    {
        std::cout << "std::this_thread::get_id() " << __FUNCTION__ << " : "
                  << std::this_thread::get_id() << std::endl;
        return a % 2 == 0;
    };
    std::cout << "std::is_object<decltype(function1)>::value:   "
              << std::is_object<decltype(function1)>::value << std::endl;
    std::cout << "call function1(1023): " << function1(1023) << std::endl;
    std::cout << "call function1(1024): " << function1(1024) << std::endl;
    std::cout << "typeid(function1).name():     "
              << typeid(function1).name() << std::endl;
    std::cout << std::endl;
    std::function<bool(int)> function2 = function1;
    std::cout << "std::is_object<decltype(function2)>::value:   "
              << std::is_object<decltype(function2)>::value << std::endl;
    std::cout << "call function2(1023): " << function2(1023) << std::endl;
    std::cout << "call function2(1024): " << function2(1024) << std::endl;
    std::cout << "typeid(function2).name():     "
              << typeid(function2).name() << std::endl;
    std::cout << std::endl;
    std::packaged_task<bool(int)> function3(function2);
    std::future<bool> result1023 = function3.get_future();
    std::thread thread(std::move(function3), 1024);
    thread.join();
    std::cout << "std::is_object<decltype(function3)>::value:   "
              << std::is_object<decltype(function3)>::value << std::endl;
    std::cout << "call function3(1023): " << result1023.get() << std::endl;
    std::cout << "typeid(function3).name():     "
              << typeid(function3).name() << std::endl;
    std::cout << std::endl;
    std::once_flag flag1;
    std::call_once(flag1, function2, 1024);
    std::async(std::launch::async, function2, 1024);
    std::async(std::launch::deferred, function2, 1024);
    return 0;
}
输出
std::is_object<decltype(function1)>::value:   true
std::this_thread::get_id() operator() : 1
call function1(1023): false
std::this_thread::get_id() operator() : 1
call function1(1024): true
typeid(function1).name():     Z4mainEUliE_
std::is_object<decltype(function2)>::value:   true
std::this_thread::get_id() operator() : 1
call function2(1023): false
std::this_thread::get_id() operator() : 1
call function2(1024): true
typeid(function2).name():     St8functionIFbiEE
std::this_thread::get_id() operator() : 2
std::is_object<decltype(function3)>::value:   true
call function3(1023): true
typeid(function3).name():     St13packaged_taskIFbiEE
std::this_thread::get_id() operator() : 1
std::this_thread::get_id() operator() : 3本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!