广告推广系统seo关键词软件

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

广告推广系统,seo关键词软件,wordpress如何本地安装,北京企业网站建站哪家好C进阶专栏#xff1a;http://t.csdnimg.cn/5mV9r 目录 1.概述 2.辅助类 3.原理分析 4.总结 1.概述 在之前的 C 版本中#xff0c;要调用不同类型的可调用对象#xff0c;需要使用不同的语法#xff0c;例如使用函数调用运算符 () 来调用函数或函数指针#xff0c;使用… C进阶专栏http://t.csdnimg.cn/5mV9r 目录 1.概述 2.辅助类 3.原理分析 4.总结 1.概述 在之前的 C 版本中要调用不同类型的可调用对象需要使用不同的语法例如使用函数调用运算符 () 来调用函数或函数指针使用成员访问运算符 - 或 . 来调用成员函数。这样的语法差异导致了代码的冗余和不一致给编写和维护代码带来了困扰。 std::invoke 是 C17标准库中引入的一个函数模板它的引入就是为了解决这个问题它提供了一种统一的调用语法无论是调用普通函数、函数指针、类成员函数指针、仿函数、std::function、类成员还是lambda表达式都可以使用相同的方式进行调用。 std::invoke 的语法如下 template typename Fn, typename… Args decltype(auto) invoke(Fn fn, Args… args); 它接受一个可调用对象 fn 和相应的参数 args…并返回调用结果。例如 #include functional #include iostream #include typetraitsstruct Foo {Foo(int num) : num(num) {}void printadd(int i) const { std::cout num i \n; }int num_; };void print_num(int i) {std::cout i \n; }struct PrintNum {void operator()(int i) const{std::cout i \n;} };int main() {// 调用自由函数std::invoke(print_num, -9);// 调用 lambdastd::invoke( { print_num(42); });// 调用成员函数const Foo foo(314159);std::invoke(Foo::printadd, foo, 1);// 调用访问数据成员std::cout num std::invoke(Foo::num_, foo) \n;// 调用函数对象std::invoke(PrintNum(), 18);#if defined(__cpp_lib_invoke_r)auto add { return x y; };auto ret std::invoke_rfloat(add, 11, 22);static_assert(std::is_samedecltype(ret), float());std::cout ret \n;std::invoke_rvoid(print_num, 44); #endif } 可能的输出 -9 42 314160 num_314159 18 33 44 通过 std::invoke我们可以在不关心可调用对象的具体类型的情况下进行调用提高了代码的灵活性和可读性。它尤其适用于泛型编程中需要以统一方式调用各种可调用对象的场景例如使用函数指针或成员函数指针作为模板参数的算法或容器等。 2.辅助类 阅读后面的内容你必须事先了解以下内容 1.constexpr 2.std::is_base_of_v 3.std::remove_cv_t 4.std::ref和std::cref 5.std::is_member_function_pointer 6.std::is_member_object_pointer_v 7.左值和右值 3.原理分析 从上面的例子我们可以猜想std::invoke的实现应该是根据传入的参数Fn来判断出Fn是否为可调用对象(Callable)常见的可调用对象有 function member functionfunction objectlambda expressionbind expressionstd::function 如果是可调用对象那肯定也需要分析出是那种可调用对象C涉及到的可调用对象有 1.普通函数保证了对C的兼容。如void  func(int x, int y); 2.函数指针。和数组名一样函数名即为函数指针。如 typedef void(FType)(int); //定义一个函数指针类型Ftypevoid func(FType fn, int x) {fn(x);} 3.类成员变量和成员函数 class CTestabcd{public:inline int func(int a, int b) { return a b; }public:int m_i;};using TestFunc int (CTestabcd::)(int, int);using TestMember int(CTestabcd::*);TestFunc gTestFunc CTestabcd::func;TestMember gTestMember CTestabcd::m_i; 4.仿函数(函数对象)即重载了operator()运算符的类对象如 template class _Ty voidstruct less {_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty _FIRST_ARGUMENT_TYPE_NAME;_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty _SECOND_ARGUMENT_TYPE_NAME;_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef bool _RESULT_TYPE_NAME;_NODISCARD constexpr bool operator()(const _Ty _Left, const _Ty _Right) const {return _Left _Right;}}; std::bind绑定它是STL的配接器用于创建一个可调用的对象对象里面重载了operator()也是运用了仿函数的思想如:  #include iostream
#include functional
#include thread
#include chrono
#include vector
#include algorithm void print_sum(int x, int y) { std::cout x y \n;
} int main() { std::vectorint nums {1, 2, 3, 4, 5}; auto bound_sum std::bind(print_sum, std::placeholders::_1, 5); // 绑定第二个参数为 5。 std::for_each(nums.begin(), nums.end(), bound_sum); // 对于每个元素输出它与 5 的和。 return 0;
} 5.lambda表达式如 auto f [] { return hello world; }; cout f() endl; // 输出hello world 6.std::function, 如 #include iostream #include functional// std::function std::functionint(int, int) SumFunction;// 普通函数 int func_sum(int a, int b) {return a b; }class Calcu { public:int base 20;// 类的成员方法参数包含this指针int class_func_sum(const int a, const int b) const { return this-base a b; };// 类的静态成员方法不包含this指针static int class_static_func_sum(const int a, const int b) { return a b; }; };// 仿函数 class ImitateAdd { public:int operator()(const int a, const int b) const { return a b; }; };// lambda函数 auto lambda_func_sum - int { return a b; };// 函数指针 int (func_pointer)(int, int);int main(void) {int x 2; int y 5;// 普通函数SumFunction func_sum;int sum SumFunction(x, y);std::cout func_sum sum std::endl;// 类成员函数Calcu obj;SumFunction std::bind(Calcu::class_func_sum, obj, std::placeholders::_1, std::placeholders::_2); // 绑定this对象sum SumFunction(x, y);std::cout Calcu::class_func_sum sum std::endl;// 类静态函数SumFunction Calcu::class_static_func_sum;sum SumFunction(x, y);std::cout Calcu::class_static_func_sum sum std::endl;// lambda函数SumFunction lambda_func_sum;sum SumFunction(x, y);std::cout lambda_func_sum sum std::endl;// 带捕获的lambda函数int base 10;auto lambda_func_with_capture_sum base-int { return x y base; };SumFunction lambda_func_with_capture_sum;sum SumFunction(x, y);std::cout lambda_func_with_capture_sum sum std::endl;// 仿函数ImitateAdd imitate;SumFunction imitate;sum SumFunction(x, y);std::cout imitate func sum std::endl;// 函数指针func_pointer func_sum;SumFunction func_pointer;sum SumFunction(x, y);std::cout function pointer sum std::endl;getchar();return 0; } 通过上面的讲解那我们看看std::invoke是不是这样去判断的呢(以vs2019为蓝本)先看看源码 //[1]函数没有参数的调用方式 template class _Callable _CONSTEXPR17 auto invoke(_Callable _Obj) noexcept(noexcept(static_cast_Callable(_Obj)()))- decltype(static_cast_Callable(_Obj)()) {return static_cast_Callable(_Obj)(); }//[2]除1之外的其他调用方式 template class _Callable, class _Ty1, class… _Types2 _CONSTEXPR17 auto invoke(_Callable _Obj, _Ty1 _Arg1, _Types2… _Args2) noexcept(noexcept(_Invoker1_Callable, _Ty1::_Call(static_cast_Callable(_Obj), static_cast_Ty1(_Arg1), static_cast_Types2(_Args2)…)))- decltype(_Invoker1_Callable, _Ty1::_Call(static_cast_Callable(_Obj), static_cast_Ty1(_Arg1), static_cast_Types2(_Args2)…)) {if constexpr (_Invoker1_Callable, _Ty1::_Strategy _Invoker_strategy::_Functor) {return static_cast_Callable(_Obj)(static_cast_Ty1(_Arg1), static_cast_Types2(_Args2)…);} else if constexpr (_Invoker1_Callable, _Ty1::_Strategy _Invoker_strategy::_Pmf_object) {return (static_cast_Ty1(_Arg1)._Obj)(static_cast_Types2(_Args2)…);} else if constexpr (_Invoker1_Callable, _Ty1::_Strategy _Invoker_strategy::_Pmf_refwrap) {return (_Arg1.get().*_Obj)(static_cast_Types2(_Args2)…);} else if constexpr (_Invoker1_Callable, _Ty1::_Strategy _Invoker_strategy::_Pmf_pointer) {return ((static_cast_Ty1(_Arg1))._Obj)(static_cast_Types2(_Args2)…);} else if constexpr (_Invoker1_Callable, _Ty1::_Strategy _Invoker_strategy::_Pmd_object) {return static_cast_Ty1(_Arg1)._Obj;} else if constexpr (_Invoker1_Callable, _Ty1::_Strategy _Invoker_strategy::_Pmd_refwrap) {return _Arg1.get()._Obj;} else {static_assert(_Invoker1_Callable, _Ty1::_Strategy _Invoker_strategy::_Pmd_pointer, bug in invoke);return (static_cast_Ty1(_Arg1))._Obj;} } 从上面的代码可以看到传入参数 _Obj 的型别判断是通过类 _Invoker1 类型萃取出来的这就是Type Traits技术。那现在来看一下_Invoker1的庐山真面目吧 //【1】 template class _Callable, class _Ty1, class _Removed_cvref _Remove_cvref_t_Callable,bool _Is_pmf is_member_function_pointer_v_Removed_cvref,bool _Is_pmd is_member_object_pointer_v_Removed_cvref struct _Invoker1;//【2】 template class _Callable, class _Ty1, class _Removed_cvref struct _Invoker1_Callable, _Ty1, _Removed_cvref, true, false: conditional_tis_base_of_vtypename _Is_memfunptr_Removed_cvref::_Class_type, remove_reference_t_Ty1,_Invoker_pmf_object,conditional_t_Is_specialization_v_Remove_cvref_t_Ty1, reference_wrapper, _Invoker_pmf_refwrap,_Invoker_pmf_pointer {}; // pointer to member function//【3】 template class _Callable, class _Ty1, class _Removed_cvref struct _Invoker1_Callable, _Ty1, _Removed_cvref, false, true: conditional_tis_base_of_vtypename _Is_member_object_pointer_Removed_cvref::_Class_type, remove_reference_t_Ty1,_Invoker_pmd_object,conditional_t_Is_specialization_v_Remove_cvref_t_Ty1, reference_wrapper, _Invoker_pmd_refwrap,_Invoker_pmd_pointer {}; // pointer to member data//【4】 template class _Callable, class _Ty1, class _Removed_cvref struct _Invoker1_Callable, _Ty1, _Removed_cvref, false, false : _Invoker_functor {}; 1在【1】处通过 is_member_function_pointer_v 判断是类成员函数指针通过 is_member_object_pointer_v 判断是类成员变量 2在【2】处指示的的是类成员函数指针判断参数_Arg1是否为reference_wrapper类型的即是传入对象添加了std::ref或std::cref包装。 3在【3】处指示的是类成员变量指针判断参数_Arg1是否为reference_wrapper类型的即是传入对象添加了std::ref或std::cref包装。 4在【4】处指示的是除【2】【3】之外的函数。 型别推导出的类型有 enum class _Invoker_strategy {_Functor, //普通函数仿函数lamdba表达式, std::function等_Pmf_object, //类成员函数传递的是对象_Pmf_refwrap, //类成员函数传递的是用std::ref或std::cref包装了的对象_Pmf_pointer, //类成员函数传递的是对象的指针_Pmd_object, //类成员变量传递的是对象_Pmd_refwrap, //类成员变量传递的是用std::ref或std::cref包装了的对象_Pmd_pointer //类成员变量传递的是对象的指针 }; 至此std::invoke的实现原理很清晰了吧。 4.总结 std::invoke用起来是十分的方便方便的背后是系统帮你做了很多影藏的东西。也同样看出C的模版是多么的强大。如果喜欢就快去使用吧 喜欢的同学点赞收藏呗 参考std::invoke, std::invoke_r - cppreference.com