1. function_traits
(1)function_traits的作用:获取函数的实际类型、返回值类型、参数个数和具体类型等。它能获取所有函数语义类型信息。可以获取普通函数、函数指针、std::function、函数对象和成员函数等的相关信息。
(2)实现function_traits的关键技术
①通过模板特化和可变参数模板来实现。
②针对成员函数和仿函数的特化版本需要注意const和volatile版本的定义。
③function_traits函数的入参是可变参数模板,其类型和个数都是任意的,要获取指定位置的类型,可以通过std::tuple_element<N, std::tuple<Args…>>::type来获取。
【编程实验】
//function_traits.hpp
#ifndef _FUNCTION_TRAITS_H_ #define _FUNCTION_TRAITS_H_ #include <functional> #include <tuple> //普通函数 //函数指针 //function/lambda //成员函数 //函数对象 template<typename T> struct function_traits; //前向声明 //普通函数 template<typename Ret, typename... Args> struct function_traits<Ret(Args...)> { public: enum {arity = sizeof...(Args)};//arity : 参数的数量 //函数别名 typedef Ret function_type(Args...); //<==> using function_type = Ret(Args...); typedef Ret return_type; //返回值类型 using stl_function_type = std::function<function_type>; typedef Ret(*pointer)(Args...); //获取可变参数模板中第I个位置的参数类型。 template<size_t I, class = typename std::enable_if<(I<arity)>::type> using args = typename std::tuple_element<I, std::tuple<Args...>>; }; //函数指针 template<typename Ret, typename... Args> struct function_traits<Ret(*)(Args...)> : function_traits<Ret(Args...)>{}; //std::function template<typename Ret, typename... Args> struct function_traits<std::function<Ret(Args...)>> : function_traits<Ret(Args...)>{}; //成员函数 #define FUNCTION_TRAITS(...) \ template <typename ReturnType, typename ClassType, typename... Args> \ struct function_traits<ReturnType(ClassType::*)(Args...) __VA_ARGS__> : function_traits<ReturnType(Args...)>{}; FUNCTION_TRAITS() FUNCTION_TRAITS(const) //const成员函数 FUNCTION_TRAITS(volatile) FUNCTION_TRAITS(const volatile) //函数对象 template<typename Callable> struct function_traits : function_traits<decltype(&Callable::operator())>{}; //将lambda转为std::function template<typename Function> typename function_traits<Function>::stl_function_type to_function(const Function& lambda) { return static_cast<typename function_traits<Function>::stl_function_type>(std::forward<Function>(lambda)); } template<typename Function> typename function_traits<Function>::stl_function_type to_function(Function&& lambda) { return static_cast<typename function_traits<Function>::stl_function_type>(lambda); } //将lambda转为函数指针,如 template<typename Function> typename function_traits<Function>::pointer to_function(const Function& lambda) { // typedef int(*FUN)(int); // auto f = FUN([](int x){return x + 10;}); // cout << f(10) << endl; //20 return static_cast<typename function_traits<Function>::pointer>(lambda); } #endif //_FUNCTION_TRAITS_H_
//test_function_traits.cpp
#include <iostream> #include <typeinfo> #include "function_traits.hpp" using namespace std; template<typename T> void PrintType() { cout << typeid(T).name() << endl; } float (*castfunc)(string, int); float free_function(const string& a, int b) { return (float) a.size() / b; } struct Test { int func(int a, int b) volatile { return a + b; } int operator()(int) const { return 0; } }; void TestFunctionTraits() { std::function<int(int)> f = [](int a){return a;}; PrintType<function_traits<std::function<int(int)>>::function_type>(); //FiiE PrintType<function_traits<std::function<int(int)>>::args<0>::type>(); //i PrintType<function_traits<decltype(f)>::function_type>(); PrintType<function_traits<decltype(free_function)>::function_type>(); PrintType<function_traits<decltype(castfunc)>::function_type>(); PrintType<function_traits<Test>::function_type>(); //FiiE, int operator()(int) using T = decltype(&Test::func); PrintType<T>(); //M4TestVFiiiE PrintType<function_traits<decltype(&Test::func)>::function_type>(); //FiiiE cout << std::is_same<function_traits<decltype(f)>::return_type, int>::value << endl; //1 } int main() { typedef int(*FUN)(int); auto f = FUN([](int x){return x + 10;}); cout << f(10) << endl; TestFunctionTraits(); return 0; } /* //g++测试结果 E:\Study\C++11\25>g++ -std=c++11 test_function_traits.cpp E:\Study\C++11\25>a.exe 20 FiiE i FiiE FfRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEiE FfNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEiE FiiE M4TestVFiiiE FiiiE 1 //VC2015测试结果: e:\Study\C++11\25>cl test_function_traits.cpp /EHsc e:\Study\C++11\25>test_function_traits.exe 20 int __cdecl(int) int int __cdecl(int) float __cdecl(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,int) float __cdecl(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int) int __cdecl(int) int (__thiscall Test::*)(int,int)volatile int __cdecl(int,int) 1 */
2. ScopeGuard的实现
(1)ScopeGuard的作用:
①确保资源在非正常返回时总能被成功释放。(如函数在中途提前返回,或者中途抛异常而返回)
②ScopeGuard是RAII的一种泛化实现。它与RAII的不同是ScopeGuard只关注清理的部分——资源申请你来做,ScopeGuard帮你清除。清理(回收)资源有很多办法,如调用一个函数/仿函数,调用一个对象的成员函数。它们都可能需要0个,1个或多个参数。
(2)实现ScopeGuard的关键技术:
①通过局部变量析构函数来管理资源,根据是否正常退出来确定是否需要清理资源。
②通过m_dismiss标志来决定是否执行清除操作。
【编程实验】ScopeGuard的实现
//ScopeGuard.hpp
#ifndef _SCOPE_GUARD_H_ #define _SCOPE_GUARD_H_ #include <iostream> using namespace std; template <typename F> class ScopeGuard { F m_func; //异常处理函数 bool m_dismiss; //正常退出为true,非正常退出时为false ScopeGuard(); ScopeGuard(const ScopeGuard&); ScopeGuard& operator=(const ScopeGuard&); public: void dismiss() { m_dismiss = true; } explicit ScopeGuard(F&& f) : m_func(f), m_dismiss(false){} explicit ScopeGuard(const F& f) : m_func(f), m_dismiss(false){} ScopeGuard(ScopeGuard&& rhs) : m_func(std::move(rhs.m_func)), m_dismiss(rhs.m_dismiss) { rhs.dismiss(); } ~ScopeGuard() { if(!m_dismiss && m_func != nullptr){ m_func(); } } }; //辅助函数 template<typename Function> ScopeGuard<typename std::decay<Function>::type> MakeGuard(Function&& f) { //调用ScopeGuard(const F& f)或ScopeGuard(F&& f) return ScopeGuard<typename std::decay<Function>::type>(std::forward<Function>(f)); } #endif
//test_ScopeGuard.cpp
#include <iostream> #include <functional> #include <exception> #include "ScopeGuard.hpp" using namespace std; void TestScopeGuard() { //资源清理函数 std::function<void()> f = []{cout << "clean up from unnormal exit" << endl;}; //正常退出 { auto gd = MakeGuard(f); //... 在MakeGuard和dismiss之间的操作是异常安全的。一旦出现导常,导致gd在 // 离开作用域时,会调用传入在MakeGuard中注册的清理函数进行释放资源。 gd.dismiss(); //解除ScopeGuard } //异常退出 { auto gd = MakeGuard(f); //... 其它操作,假设在这里出现异常。由于这里的代码被MakeGuard保护 //所以异常发生时,仍会调用清理函数来正确释放资源 throw std::exception(std::out_of_range("excetion occur!")); gd.dismiss(); } //非正常退出 { auto gd = MakeGuard(f); return; gd.dismiss(); } } int main() { TestScopeGuard(); return 0; }
原文链接: https://www.cnblogs.com/5iedu/p/7853337.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;
也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/392835
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!