当前位置: 首页 > article >正文

C++ function 源码分析(5):is_const_v<const 函数> = False ,源码注释及资源

(23) is_const_v<const 函数> = False , 这是识别函数类型的重要概念。来自于 STL 库源码

在这里插入图片描述

++ 下面的源代码所在的头文件 , D:\vs2019\VC\Tools\MSVC\14.29.30133\include\type_traits :

在这里插入图片描述

++ 函数类型,在编译时候会加上函数签名的,所以编译器可以确定一个类型是函数类型,然后赋值 is_const_v<const 函数> = False :

在这里插入图片描述

(24) 给出 function 模板类的源码注释,本文一并附上资源。 vs2019 c++20 规范的 STL 头文件 :

// functional standard header

// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#pragma once

#ifndef _FUNCTIONAL_
#define _FUNCTIONAL_

#include <yvals_core.h>

#if _STL_COMPILER_PREPROCESSOR
#include <exception>
#include <tuple>
#include <typeinfo>
#include <xmemory>
#include <xstddef>

#if _HAS_CXX17
#include <memory>
#include <unordered_map>
#endif // _HAS_CXX17

#ifdef __cpp_lib_concepts
#include <compare>
#endif // __cpp_lib_concepts

#pragma pack(push, _CRT_PACKING) 
// 以下的结构体以及 union 将采用 8 字节对齐。入栈原来的对齐方式 _CRT_PACKING = 8

#pragma warning(push, _STL_WARNING_LEVEL)
//调整本源文件编译时候的警告级别,是较减少了警告。 _STL_WARNING_LEVEL = 3
// 0 不警告,4 全警告。并把原来的警告级别入栈

#pragma warning(disable : _STL_DISABLED_WARNINGS)
//#define  _STL_DISABLED_WARNINGS  4180 4412 4455 4494 4514 4574 ......
// 表示禁用这些警告,忽略这些警告 <yvals_core.h>

_STL_DISABLE_CLANG_WARNINGS
// 按字面意思,禁止 clang 警告,最后还有对应的 宏定义,_STL_RESTORE_CLANG_WARNINGS

#pragma push_macro("new")
#undef new
// 入栈系统之前的 new 的宏定义,并取消此宏定义。可能要自己定义内存管理方式

_STD_BEGIN
// #define _STD_BEGIN namespace std {  表示以下内容全部定义于  std  命名空间

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

// 这像是一个函数的声明,功能像是销毁 类exception 里的堆区的字符串
void __cdecl __std_exception_destroy(_Inout_ __std_exception_data* _Data);

struct __std_exception_data { char const* _What;    bool _DoFree; };

class exception // 这只是摘抄的 exception 的不完整的定义,利于此处子类 bad_function_call 的理解
{
private:
    __std_exception_data _Data; // 此数据成员的定义在上面
public:
    exception() noexcept : _Data() { } // 默认的空初始化

    virtual ~exception() noexcept { __std_exception_destroy(&_Data); } // 父类的虚析构函数

    _NODISCARD virtual char const* what() const // 父类的虚成员函数,返回本类里保存的字符串的地址
    {
        return _Data._What ? _Data._What : "Unknown exception";
    }
};

class bad_function_call : public exception // public 继承
{   // exception thrown when an empty std::function is called
public:
    bad_function_call() noexcept {}

    virtual const char*  what() const noexcept override // override 父类中的此函数
    {   // return pointer to message string
        return "bad function call"; // 字符串常量,属于进程级别的
    }
};

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

// tag to distinguish bind() from bind<R>()
struct _Unforced {   explicit _Unforced() = default;   };

// template <class _Ty>
// constexpr bool is_void_v = is_same_v<remove_cv_t<_Ty>, void>;
// 模板类与类的特化。_Rx 代表函数的返回值类型,当函数的返回值为 void 时选择此泛化类版本
template <class _Rx, bool = is_void_v<_Rx>> // selected for _Rx being cv void
struct _Invoker_ret  
{
    template <class _Fx, class... _Valtys>  // 类的静态成员函数,不带返回值
    static void _Call(_Fx&& _Func, _Valtys&&... _Vals) 
    {    _STD invoke(static_cast<_Fx&&>(_Func), static_cast<_Valtys&&>(_Vals)...);  }
};

template <class _Rx> // 模板类的特化版本一
struct _Invoker_ret<_Rx, false>
{   // selected for all _Rx other than cv void and _Unforced;为所有Rx选择,除了void和Unforced
    template <class _Fx, class... _Valtys>            // 类的静态成员函数,带返回值
    static _Rx _Call(_Fx&& _Func, _Valtys&&... _Vals) // INVOKE, implicitly converted to _Rx
    { 
        return _STD invoke(static_cast<_Fx&&>(_Func), static_cast<_Valtys&&>(_Vals)...);
    }
};

template <>          // 模板类的特化版本二,函数的返回值是 _Unforced 类型,实际采用了 auto 推导
struct _Invoker_ret<_Unforced, false> 
{                    // selected for _Rx being _Unforced;选择_Rx为_Unforced
    template <class _Fx, class... _Valtys> 
    static auto _Call(_Fx&& _Func, _Valtys&&... _Vals) 
        -> decltype(_STD invoke(static_cast<_Fx&&>(_Func), static_cast<_Valtys&&>(_Vals)...)) 
    { return _STD invoke(static_cast<_Fx&&>(_Func), static_cast<_Valtys&&>(_Vals)...); }
};

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

template <class _Fty>
class function;

template <class _Ty>                   // conj 要求所有的条件都为真,才为真,继续往下执行;
constexpr bool _Testable_callable_v =  // disj 要求所有的参数都为假,才为假。
    disjunction_v<is_pointer<_Ty>, _Is_specialization<_Ty, function>, is_member_pointer<_Ty>>;

template <class _Ty>  // 本函数的意思是倾向于返回 true, function 对象要存储内部的可执行对象
bool _Test_callable(const _Ty& _Arg) noexcept 
{ // determine whether std::function must store _Arg 确定std::函数是否必须存储_Arg
    if constexpr (_Testable_callable_v<_Ty>)        
        return !!_Arg; 
    else         
        return true;
}

// <typeinfo> 中  int _Small_object_num_ptrs = 6 + 16 / sizeof(void*) = 8 ;  64 位系统
constexpr size_t _Space_size = (_Small_object_num_ptrs - 1) * sizeof(void*); //= 56 字节
// 本值是可在 function 对象内部的 64 字节空间里构造的可调用对象的最大大小,即是不超过 56 字节
// 再大的可调用对象,就要在堆区构造
// 因 _Func_impl_no_alloc 对象含有虚函数表指针,故又限制可调用对象 <= 48 字节。

template <class _Impl>
constexpr bool _Is_large = sizeof(_Impl) > _Space_size  // using max_align_t = double; 
|| alignof(_Impl) > alignof(max_align_t) // 未按照 8 字节对齐  
|| !_Impl::_Nothrow_move::value; //当可调用对象的 move构造函数 缺乏 noecept修饰,也在堆区构造

// __declspec(novtable) 让本类不要有虚函数表以及对虚函数表的初始化代码, 这样可以节省运行时间和空间. 
// 本类的派生类,子类,会自己包含自己的虚函数表和初始化代码.
template <class _Rx, class... _Types>
class __declspec(novtable) _Func_base
{   
public:  // 本模板类未定义析构函数
    _Func_base() = default; // 默认的空构造函数
    _Func_base(const _Func_base&) = delete; // 禁止的 copy 构造函数  
    _Func_base& operator=(const _Func_base&) = delete; // 禁止的 copy 赋值运算符函数

    virtual void _Delete_this(bool) noexcept  = 0; // 若本模板包含的大可调用对象在堆区,退出前析构之
    virtual _Func_base* _Copy(void*) const    = 0; // 把自己存储的可调用对象 copy 至 _Where 处
    virtual _Func_base* _Move(void*) noexcept = 0; // 把自己存储的可调用对象 move 至 _Where 处
    virtual _Rx _Do_call(_Types&&...)         = 0; // 函数调用的虚接口_Do_call
    virtual const type_info& _Target_type() const noexcept = 0; // 返回本模板包含的可调用对象的类型
   
    const void* _Target(const type_info& _Info) const noexcept
    {   // 返回本模板包含的可调用对象的地址。相当于从智能指针里扒出裸指针
        return _Target_type() == _Info ? _Get() : nullptr;    
    }
private: // 父类的私有的虚成员函数,子类无法使用; 但子类可以重定义此虚函数(也可重定义其可见性),
    virtual const void* _Get() const noexcept = 0; // 然后子类就可以自己版本的此虚函数
    // return _STD addressof( _Func_impl_no_alloc._Callee );
};

// 模板参数 _Rx 与 _Types... 传递给了父类
template <class _Callable, class _Rx, class... _Types>
class _Func_impl_no_alloc final : public _Func_base<_Rx, _Types...>
{   
private:
    _Callable _Callee;  // 函数地址, 8 字节。或可调用对象
public:
    using _Mybase = _Func_base<_Rx, _Types...>; // move 构造函数有 except 修饰则为 True
    using _Nothrow_move = is_nothrow_move_constructible<_Callable>;

    //struct enable_if<true, _Ty> {  using type = _Ty; };
    template <class _Other, enable_if_t<!is_same_v<_Func_impl_no_alloc, decay_t<_Other>>, int> = 0>
    explicit _Func_impl_no_alloc(_Other&& _Val) : _Callee(_STD forward<_Other>(_Val)) { } //显式构造

private:  // 依次实现父类里的虚函数   
    virtual _Mybase* _Copy(void* _Where) const override
    {    // 注意 copy 的方向:把自己的 _Callee 成员 copy 至 _Where 处
        if constexpr (_Is_large<_Func_impl_no_alloc>)
        {
            (void) _Where; // TRANSITION, DevCom-1004719
            return _Global_new<_Func_impl_no_alloc>(_Callee);
        }
        else 
            return ::new (_Where) _Func_impl_no_alloc(_Callee);
    }

    virtual _Mybase* _Move(void* _Where) noexcept override 
    {   // 把自己存储的可调用对象 move 至 _Where 处
        if constexpr (_Is_large<_Func_impl_no_alloc>) 
        {
            (void) _Where; // TRANSITION, DevCom-1004719
            return nullptr;
        } 
        else 
            return ::new (_Where) _Func_impl_no_alloc(_STD move(_Callee));
    }

    virtual _Rx _Do_call(_Types&&... _Args) override  // call wrapped function
    {   // 根据函数类型,选择上面的 _Invoker_ret<T> 三个版本中的一个执行
        return _Invoker_ret<_Rx>::_Call(_Callee, _STD forward<_Types>(_Args)...);   
    }

    virtual const type_info& _Target_type() const override { return typeid(_Callable); }

    virtual const void* _Get() const override { return _STD addressof(_Callee); }

    virtual void _Delete_this(bool _Dealloc) noexcept override  // destroy self
    { 
        this->~_Func_impl_no_alloc();  // 并未有明确定义的析构函数,反汇编显示此行被直接略过
        
        // void _Deallocate(void* _Ptr, size_t _Bytes) { ::operator delete(_Ptr); }
        if (_Dealloc) // 当本对象太大 >= 56 字节,定义在堆区,则形参 _Dealloc 为 true
            _Deallocate<alignof(_Func_impl_no_alloc)>(this, sizeof(_Func_impl_no_alloc));
    }

};

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

template <class... _Types>
struct _Arg_types {}; // provide argument_type, etc. when sizeof...(_Types) is 1 or 2

template <class _Ty1>
struct _Arg_types<_Ty1> {
    typedef _Ty1 _ARGUMENT_TYPE_NAME;
};

template <class _Ty1, class _Ty2>
struct _Arg_types<_Ty1, _Ty2> {
    typedef _Ty1 _FIRST_ARGUMENT_TYPE_NAME ;
    typedef _Ty2 _SECOND_ARGUMENT_TYPE_NAME;
};

template <class _Ret, class... _Types>  // _Ret 与 _Types 分别是模板要求的返回值类型与参数类型
class _Func_class : public _Arg_types<_Types...>   // 本模板是 function 模板的父类 
{   // 本对象具有 64 字节的大小,占据 64 字节的内存空间
public:
    using result_type = _Ret;
    using _Ptrt = _Func_base<_Ret, _Types...>;  // 注意,是代表又一个 _Func_base 模板

private:
    union _Storage // 存储小的可调用对象 ;  dummy 假的虚拟的
    {       
        max_align_t _Dummy1; // using max_align_t = double; 8 字节
        char _Dummy2[_Space_size]; // _Dummy2[56 字节]

        // 此为 8 元素数组,存储 8 个指针,指向本类模板的指针,此数组共占 8 * 8 = 64 字节
        // <typeinfo> 中  int _Small_object_num_ptrs = 6 + 16 / sizeof(void*) = 8 ;  64 位系统
        _Ptrt* _Ptrs[_Small_object_num_ptrs]; // _Ptrs[8],共 64 字节
    };                                         

    _Storage _Mystorage; // 由分析可知 ,为此 _Storage 分配了 64 字节。 

    enum { _EEN_IMPL = _Small_object_num_ptrs - 1 };  // 变量 _EEN_IMPL = 7

    // 返回本对象存储的可调用对象的地址,返回的是父类 _Func_base<_Ret, _Types...> 类型的指针
    _Ptrt* _Getimpl() { return _Mystorage._Ptrs[_Small_object_num_ptrs - 1]; } 
    
    // 判断可调用对象是否在本类的 64字节空间 中构造与存储,是则返回 true
    bool _Local() {    return _Getimpl() == static_cast<const void*>(&_Mystorage);    }
    
    // 保存 function对象 封装的可调用对象的位置,然后才可以把 function对象 当函数调用
    void _Set(_Ptrt* _Ptr) { _Mystorage._Ptrs[_Small_object_num_ptrs - 1] = _Ptr; }  

public :
    _Func_class() noexcept {  _Set(nullptr);   }  // 默认构造函数,本类只有这一个构造函数

    _Ret operator()(_Types... _Args) const // 重载了括号运算符,且是作为 functional 的基类
    {   
        if (_Empty())            _Xbad_function_call();
        //[[noreturn]] void _cdecl _Xbad_function_call(); 来自别的文件里的一个函数

        const auto _Impl = _Getimpl();
        return _Impl->_Do_call(_STD forward<_Types>(_Args)...);
    }

    ~_Func_class() noexcept {  _Tidy();    }

protected:
    bool _Empty() const noexcept { return !_Getimpl(); }

    void _Tidy() noexcept
    {
        if (!_Empty()) // destroy callable object and maybe delete it
        { 
            _Getimpl()->_Delete_this(!_Local());
            _Set(nullptr);
        }
    }

    template <class _Fx, class _Function>    //  conj 的所有条目都为 true 才为 true        
    using _Enable_if_callable_t = enable_if_t<  // 此模板类定义由子类 function 使用
        conjunction_v<                              
        negation<is_same<decay_t<_Fx>, _Function>>,   
        _Is_invocable_r<_Ret, _Fx, _Types...>   
                       >                       
        , int>;

    void _Reset_copy(const _Func_class& _Right)   // 把 right 里存储的可调用对象复制给自己
    { // copy _Right's stored object
        if (!_Right._Empty())
            _Set(_Right._Getimpl()->_Copy(&_Mystorage));
    }

    void _Reset_move(_Func_class&& _Right) noexcept // 把 right 里存储的可调用对象移动给自己
    { 
        if (!_Right._Empty())
            if (_Right._Local())  // move and tidy 小的可调用对象
            { 
                _Set(_Right._Getimpl()->_Move(&_Mystorage));
                _Right._Tidy();
            } else {              // steal from _Right 大的可调用对象             
                _Set(_Right._Getimpl());
                _Right._Set(nullptr);
            }
    }

    void _Swap(_Func_class& _Right) noexcept   // 交换两个 function 对象里的可调用对象
    {
        if (!_Local() && !_Right._Local())     // 都是小的可调用对象
        {
            _Ptrt* _Temp = _Getimpl();
            _Set(_Right._Getimpl());
            _Right._Set(_Temp);
        }
        else     // do three-way move
        {
            _Func_class _Temp; // 就是本模板名

            _Temp._Reset_move(_STD move(*this));
            _Reset_move(_STD move(_Right));
            _Right._Reset_move(_STD move(_Temp));
        }
    }

    template <class _Fx>  // 让本 function 对象关联到另一个可调用对象
    void _Reset(_Fx&& _Val)  // store copy of _Val 存储_Val的副本 
    {
       if (!_Test_callable(_Val))    return; 

       // template <class _Callable, class _Rx, class... _Types> 模板类的实例化
       // class _Func_impl_no_alloc final : public _Func_base<_Rx, _Types...> { }
       using _Impl = _Func_impl_no_alloc<decay_t<_Fx>, _Ret, _Types...>;  
       // decay_t<_Fx> 已变为函数指针类型或可调用对象的类型

        if constexpr (_Is_large<_Impl>) // dynamically allocate _Val 
            _Set(_Global_new<_Impl>(_STD forward<_Fx>(_Val)));
        else             // store _Val in-situ
            _Set(::new (static_cast<void*>(&_Mystorage)) _Impl(_STD forward<_Fx>(_Val)));
    }

    const type_info& _Target_type() const noexcept // 返回的是本 function 对象包含的可调用对象的类型
    {   // return typeid( _Func_impl_no_alloc._Callable );
        return _Getimpl() ? _Getimpl()->_Target_type() : typeid(void);    
    }

    // 返回本模板包含的可调用对象的地址。相当于从智能指针里扒出裸指针
    const void* _Target(const type_info& _Info) const noexcept
    {   // return _STD addressof( _Func_impl_no_alloc._Callee ); 
        return _Getimpl() ? _Getimpl()->_Target(_Info) : nullptr;    
    }   
};

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

template <class>
constexpr bool _Always_false = false;

template <class _Tx> //模板参数不匹配,进入这一分支,则会报错,      
struct _Get_function_impl   // 说明传递给 function 的模板参数的格式不对  
{   // 静态断言:形参1 为true则编译器继续编译,为false则编译器报错,且报错的内容为形参2
    static_assert(_Always_false<_Tx>, "std::function does not accept non-function types"
                                            " as template arguments.");
};

#define _EMIT_CDECL(FUNC, OPT1, OPT2, OPT3)  FUNC(__cdecl, OPT1, OPT2, OPT3)

#define _NON_MEMBER_CALL(FUNC, CV_OPT, REF_OPT, NOEXCEPT_OPT) \
               _EMIT_CDECL(FUNC, CV_OPT, REF_OPT, NOEXCEPT_OPT) 

#define _GET_FUNCTION_IMPL(CALL_OPT, X1, X2, X3)           \
    template <class _Ret, class... _Types>                 \
    struct _Get_function_impl<_Ret CALL_OPT(_Types...)> {  \
        using type = _Func_class<_Ret, _Types...>;         \
    };  

_NON_MEMBER_CALL(_GET_FUNCTION_IMPL, X1, X2, X3)
#undef _GET_FUNCTION_IMPL
// 根据以上的宏展开,得到宏函数的参数 X1 X2 X3 都没有意义,CALL_OPT = __cdecl
// 以上的宏定义记录不全,vs2019 的头文件里包含了所有的调用约定的定义,本机是 X64
// 但也基本说明了这段代码是如何工作的,就是为了描述函数的调用约定

//------------------------------------------------------------------------------------------------
/* function 的内存模型,代码参考上面的两个注释
(1)类function继承了_Func_class,从而获得共用体的第三项指针数组的64字节空间(这是反汇编的结论)
(2)在这64字节的开始,构造_Func_impl_no_alloc类型的变量。该_Impl存在虚继承,且其父类无成员变量
(3)虚继承的子类的构造,最开始是虚函数表基址,其次父类成员,接着子类成员。
(4)把构造完的变量地址,即64字节的开始位置,_Set填写在第7指针的位置。(从0开始数)
以下接着补充:
(5)可见,function并没有直接管理函数地址,或者称为函数指针,其只有64字节。
(6)函数地址(函数指针值)是封装在 _Func_impl_no_alloc类型的对象中,作为其数据成员 _Callee 的值。
(7)封装函数地址的_Func_impl_no_alloc类型的对象,较小的话,可以直接构造在function的64字节空间中。
(8)在function的64字节空间中的第七指针中,保存了_Func_impl_no_alloc类型的对象的地址
*/

// _Ret 是函数返回值类型,_Types 包是函数的参数类型
// 相当于 function< _Fty > : public _Func_class < _Ret , _Types... > ,
template <class _Fty>   // _Fty 是函数原型如: void ( int )
class function : public _Get_function_impl<_Fty>::type   
{     // wrapper for callable objects
private:
    using _Mybase = typename _Get_function_impl<_Fty>::type; //经推断 type = _Func_class<T>

public:
    function() noexcept {}   // 以下这些先是各种构造函数

    function(nullptr_t) noexcept {}

    //模板参数里 关键字 typename 等价于 class。形参是值传递,函数体里是移动构造
    template <class _Fx, typename _Mybase::template _Enable_if_callable_t<_Fx&, function> = 0>
    function(_Fx _Func) { this->_Reset(_STD move(_Func)); }

    function(const function& _Right) { this->_Reset_copy(_Right); }

    function(function&& _Right) noexcept {  this->_Reset_move(_STD move(_Right));  }

    // 说明 function 支持这样的写法 : function = nullptr_t  的写法
    function& operator=(nullptr_t) noexcept 
    {
        this->_Tidy();
        return *this;
    }

    // 这里的 decay_t<_Fx>& 就很神奇,形参可以是任意的可执行对象。
    template <class _Fx, typename _Mybase::template _Enable_if_callable_t<decay_t<_Fx>&, function> = 0>
    function& operator=(_Fx&& _Func)    
    {
        function(_STD forward<_Fx>(_Func)).swap(*this);
        return *this;
    }

    // 这里是赋值运算符的重载
    function& operator=(const function& _Right) 
    {
        function(_Right).swap(*this);
        return *this;
    }

    function& operator=(function&& _Right) noexcept 
    {
        if (this != _STD addressof(_Right)) 
        {
            this->_Tidy();
            this->_Reset_move(_STD move(_Right));   // _Reset_move 见上面移动构造的注释
        }
        return *this;
    }

    // reference_wrapper<T> requires T to be an object type or a function type.
    template <class _Fx>
    function& operator=(reference_wrapper<_Fx> _Func) noexcept 
    {
        this->_Tidy();
        this->_Reset(_Func);
        return *this;
    }

    // 调用了父类的 proteced 权限的成员函数 _Func_class._Swap(_Func_class& _Right)
    void swap(function& _Right) noexcept {     this->_Swap(_Right);    }

    // 显式类型转换运算符,若本 function 绑定了可调用对象,则转换为 True
    explicit operator bool() const noexcept {   return !this->_Empty();   }   

    const type_info& target_type() const noexcept {   return this->_Target_type();  }
    /*
    template <class _Rx, class... _Types>
    class __declspec(novtable) _Func_base
    {
        virtual const type_info& _Target_type() const noexcept = 0;

        const void* _Target(const type_info& _Info) // 注意此函数并非虚函数
        {    return _Target_type() == _Info ? _Get() : nullptr;    }

        virtual const void* _Get() const noexcept = 0;
    };

    template <class _Callable, class _Rx, class... _Types>
    class _Func_impl_no_alloc final : public _Func_base<_Rx, _Types...>
    {
        _Callable _Callee;

        virtual const void* _Get() const override { return _STD addressof(_Callee); }

        virtual const type_info& _Target_type() const override { return typeid(_Callable); }
    };  // 可见,最终返回的是 function 封装的可调用对象的类型

    template <class _Ret, class... _Types>  // function 的父类
    class _Func_class : public _Arg_types<_Types...>
    {
        const type_info& _Target_type() const noexcept
        {   return _Getimpl() ? _Getimpl()->_Target_type() : typeid(void);    }

        const void* _Target(const type_info& _Info) const noexcept
        {   return _Getimpl() ? _Getimpl()->_Target(_Info) : nullptr;    }
    };
    */
    template <class _Fx>   // 这种写法的话,模板参数是推断不出来的,要明确指定。
    _Fx* target()          // 返回 function 封装的可调用对象的地址
    {                      // 此 target 函数主要是对可调用对象有意义。
        return reinterpret_cast<_Fx*>(  // 对于普通函数没意义,还会出错。
            const_cast<void*>(this->_Target(typeid(_Fx)))
                                        );
    }

    template <class _Fx>   // 类似于从智能指针里提取裸指针,从 string 里提取字符串
    const _Fx* target() const  // 适合于常量的 function 对象
    {  
        return reinterpret_cast<const _Fx*>(
                               this->_Target(typeid(_Fx))
                                                 );
    }

};

template <class _Fty>
void swap(function<_Fty>& _Left, function<_Fty>& _Right) noexcept { _Left.swap(_Right); }

template <class _Fty>
bool operator==(const function<_Fty>& _Other, nullptr_t) noexcept { return !_Other; }

_STD_END 
// #define _STD_END   } ,在 std  命名空间里的操作结束

#pragma pop_macro("new") 
// 恢复最开始隐藏的 new 宏定义,#pragma push_macro("new")

_STL_RESTORE_CLANG_WARNINGS
// 对应最开始的,此处是恢复 clang 警告

#pragma warning(pop)
// 恢复原来的警告级别  #pragma warning(push, _STL_WARNING_LEVEL)

#pragma pack(pop)
// 恢复原来的内存对齐方式  #pragma pack(push, _CRT_PACKING) 

#endif // _STL_COMPILER_PREPROCESSOR,本文件在此 #if 成立时才存在
 
#endif // _FUNCTIONAL_  防卫式声明

(25)

谢谢


http://www.kler.cn/a/406776.html

相关文章:

  • 科研深度学习:如何精选GPU以优化服务器性能
  • Python 使用 Token 认证方案连接 Kubernetes (k8s) 的详细过程
  • 全面提升系统安全:禁用不必要服务、更新安全补丁、配置防火墙规则的实战指南
  • 服务器产品
  • 数据库表设计范式
  • Linux无sudo权限将zsh作为默认shell
  • 【Vue】 npm install amap-js-api-loader指南
  • ORM思想
  • 目标检测模型优化与部署
  • 钉钉报销集成金蝶付款单的技术实现方案
  • AtCoder Beginner Contest 381 E - 11/22 Subsequence
  • Golang基础
  • 使用命令行创建 Maven 项目
  • 文件的摘要算法(md5、sm3、sha256、crc)
  • 【LeetCode热题100】队列+宽搜
  • 企业OA管理系统:Spring Boot技术实践与案例分析
  • 了解大模型:开启智能科技的新篇章
  • ubuntu增加swap交换空间
  • SpringMVC应用专栏介绍
  • 全面解析 JMeter 前置处理器:概念、工作原理与应用场景
  • 归并排序:数据排序的高效之道
  • 【大数据学习 | Spark-Core】RDD的概念与Spark任务的执行流程
  • 自动驾驶概念
  • Java将PDF保存为图片
  • 【H2O2|全栈】JS进阶知识(八)ES6(4)
  • socket连接封装