欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 手游 > C++ function 源码分析(5):is_const_v<const 函数> = False ,源码注释及资源

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

2025/11/4 0:00:05 来源:https://blog.csdn.net/zhangzhangkeji/article/details/143995074  浏览:    关键词: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 stringreturn "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和Unforcedtemplate <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为_Unforcedtemplate <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::函数是否必须存储_Argif 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_callvirtual 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 修饰则为 Trueusing _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-1004719return _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-1004719return 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 2template <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字节空间 中构造与存储,是则返回 truebool _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 objectif (!_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则编译器报错,且报错的内容为形参2static_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 绑定了可调用对象,则转换为 Trueexplicit 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)

谢谢

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词