<future> 注释5:类 _Deferred_async_state<Rx>、_Task_async_state<Rx>,推导函数返回值的类 _Invoke_result_t<Fn,arg...>

(18)类 _Deferred_async_state、_Task_async_state ,这两个类,类名都包含 state ,这俩类也是模板类 _Associated_state 的孙子类,也保存了函数的返回值。区分开定义两个孙子类,也是为了区分延时执行函数,和在新线程中执行函数:

// 这是 管理函数返回值的 _Associated_state<T> 的孙子类。要执行的函数是无参的 _Rx() 形式
template <class _Rx> // class for managing associated synchronous state for deferred execution from async
class _Deferred_async_state : public _Packaged_state<_Rx()> // 用于管理从异步延迟执行的关联同步状态的类
{
public: // 指定了函数不带参数的原因在于类 _Fake_no_copy_callable_adapter<T...> 
    template <class _Fty2>  // 构造函数,形参是不带参数的可调用对象。
    _Deferred_async_state(const _Fty2& _Fnarg) : _Packaged_state<_Rx()>(_Fnarg) {}

    template <class _Fty2>  // 构造函数,形参是不带参数的可调用对象。
    _Deferred_async_state(_Fty2&& _Fnarg) : _Packaged_state<_Rx()>(_STD forward<_Fty2>(_Fnarg)) {}  
private:
    // this function is considered to be deferred until it's invoked 此函数被认为是延迟的,直到它被调用
    virtual bool _Has_deferred_function() override {  return !this->_Running; } // 重写虚函数

    virtual void _Run_deferred_function(unique_lock<mutex>& _Lock) override // run the deferred function 
    {
        _Lock.unlock(); // 传递锁进来,是为了解锁,只有写返回值时候才需要加锁。其余时候不必要一直持有锁
        _Packaged_state<_Rx()>::_Call_immediate(); // _Call_immediate 中写返回值时 _Set_value(..)会再次加锁
        _Lock.lock();   // 获得锁以后再返回,保持语义的一致性;
    }
};

// class for managing associated synchronous state for asynchronous execution from async
template <class _Rx>  
class _Task_async_state : public _Packaged_state<_Rx()> // 用于管理从异步执行的关联同步状态的类
{
private:                             // 这里的 task 意思是任务,更指代的是新线程
    ::Concurrency::task<void> _Task; // 这是一个线程对象,管理新创建的线程

public:
    using _Mybase = _Packaged_state<_Rx()>;  // 简写父类,同时指出包含的是不带形参的可调用对象。
                                    // 指定了函数不带参数的原因在于类 _Fake_no_copy_callable_adapter<T...> 
    using _State_type = typename _Mybase::_State_type; //= _Associated_state<_Ty>中的 _Ty函数的返回值类型

    template <class _Fty2>           // 有参构造函数
    _Task_async_state(_Fty2&& _Fnarg) : _Mybase(_STD forward<_Fty2>(_Fnarg)) // do it now 
    {                                // lamda 表达式,创建线程任务,为本类的数据成员线程对象赋值
        _Task = ::Concurrency::create_task([this]() { this->_Call_immediate(); }    );

        this->_Running = true;       // 在构造函数中启动了新线程,来执行函数 _Call_immediate() 
    }

    // wait for completion,封装了未知函数 task.wait(..) 函数返回值未计算出来,本对象不予以析构,一直存在
    virtual void _Wait() override { _Task.wait(); } 

    virtual ~_Task_async_state() noexcept  {   _Wait();  } // 析构函数,调用了 wait 等待
    
    // return the stored result or throw stored exception
    virtual _State_type& _Get_value(bool _Get_only_once) override 
    {
        _Task.wait(); // 函数重写,在爷爷类的同名函数里,加了 等待函数执行完毕的 wait(..)
        return _Mybase::_Get_value(_Get_only_once);
    }

};

(19)推导函数返回值的类 _Invoke_result_t<Fn,arg…> , 引入 async 函数后,可以保存函数的返回值,首先是 编译器可以推断出函数的返回值类型。 STL 库大师们写的优秀极棒的代码,可以充分利用 C++ 的诸多语法,来推导出函数的返回值类型,就是接着这个类的定义。

在这里插入图片描述

++ 以下给出此模板类的源代码

//***************************************以这样的注释行来区分模板类的逻辑**********************************************

template <class _Callable>  // decltype 推断出了 函数 callable 的返回值类型
using _Decltype_invoke_zero = decltype(_STD declval<_Callable>()());  

//------------------------------

template <class _Result, bool _Nothrow>  // result 的语义是实际绑定到 function<T> 对象的函数的返回值类型
struct _Invoke_traits_common             // 无参特化版本的父类,也是有参特化版本的父类
{
    using type = _Result;
    using _Is_invocable = true_type;

    template <class _Rx>     // 函数是否可调用要分析这一行, _Rx 是 function 的模板参数对应的函数的返回值类型。
    using _Is_invocable_r = bool_constant<     // 判断转换方向  type --->  _Rx
                disjunction_v< is_void<_Rx>, _Invoke_convertible<type, _Rx>   
                                             >
};

//-------------------------------

template <class _Void, class _Callable>     // 无参泛化版本  , 大致看到都给出了否定语义,不支持函数执行
struct _Invoke_traits_zero   // selected when _Callable isn't callable with zero _Args
{
    using _Is_invocable = false_type;

    template <class _Rx>
    using _Is_invocable_r = false_type;
};

template <class _Callable>        // 无参特化版本,这是比较好理解的版本。注意给 void_t 提供了两个类型。
struct _Invoke_traits_zero<  void_t<_Decltype_invoke_zero<_Callable>>  , _Callable   >   // 出现继承
    : _Invoke_traits_common<_Decltype_invoke_zero<_Callable>, noexcept(_STD declval<_Callable>()())> {}; 

//****************************************************************************************************************

template <class _Callable, class _Ty1, class... _Types2>    
using _Decltype_invoke_nonzero = decltype(  // 依然是推断被调函数的函数定义时候的返回值类型,函数带参数时候的
    _Invoker1<_Callable, _Ty1>::
    	_Call(_STD declval<_Callable>(), _STD declval<_Ty1>(), _STD declval<_Types2>()...)
                                            );

//------------------------------------------

template <class _Void, class... _Types>  // 带形参泛化版本,不支持带参函数执行的 泛化版本,大多给出了否定语义
struct _Invoke_traits_nonzero            // selected when _Callable isn't callable with nonzero _Args
{
    using _Is_invocable = false_type;
    using _Is_nothrow_invocable = false_type;

    template <class _Rx>
    using _Is_invocable_r = false_type;
};

template <class _Callable, class _Ty1, class... _Types2>  // 带形参特化版本,也是程序不报错时选择的版本
struct _Invoke_traits_nonzero<
          void_t<_Decltype_invoke_nonzero<_Callable, _Ty1, _Types2...>>, //若此行的推断有语义,就是void
                         _Callable,  //  callable 是待执行的函数类型
                         _Ty1,       //  注意,这里存在对函数的参数包的展开
                         _Types2...  
                 >
     : _Invoke_traits_common<
                 _Decltype_invoke_nonzero<  _Callable, _Ty1, _Types2...>,
    noexcept(_Invoker1<_Callable, _Ty1>::
    		_Call(_STD declval<_Callable>(), _STD declval<_Ty1>(), _STD declval<_Types2>()...))
                                  > {};

//**********************************************************************************************************

template <class _Callable, class... _Args>
using _Select_invoke_traits = conditional_t<sizeof...(_Args) == 0,
                          _Invoke_traits_zero<void, _Callable>,
                            _Invoke_traits_nonzero<void, _Callable, _Args...>
                                               >;

template <class _Callable, class... _Args>
using _Invoke_result_t = typename _Select_invoke_traits<_Callable, _Args...>::type;

//*******************************************************************************************************************

++下面再给出 vs2019 的注释缩略图,更易于观察:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

++ 在上图中的类型推导中,用到的 decltype ( …) 的使用来确定函数的返回值。以及 void_t 的使用,见本系列的别的文章,对其有详细的说明。

(20)

谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值