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)
谢谢