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; //
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 ;
}
}; 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<>::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; //
} int main()
{
typedef int(*FUN)(int);
auto f = FUN([](int x){return x + ;});
cout << f() << endl; TestFunctionTraits(); return ;
}
/*
//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 ;
}

第25课 可变参数模板(6)_function_traits和ScopeGuard的实现的更多相关文章

  1. 第27课 可变参数模板(8)_TupleHelper

    1. TupleHelper的主要功能 (1)打印:由于tuple中的元素是可变参数模板,外部并不知道内部到底是什么数据,有时调试时需要知道其具体值,希望能打印出tuple中所有的元素值. (2)根据 ...

  2. 第26课 可变参数模板(7)_any和variant类的实现

    1. any类的实现 (1)any类: ①是一个特殊的,只能容纳一个元素的容器,它可以擦除类型,可以将何任类型的值赋值给它. ②使用时,需要根据实际类型将any对象转换为实际的对象. (2)实现any ...

  3. 第24课 可变参数模板(5)_DllHelper和lambda链式调用

    1. dll帮助类 (1)dll的动态链接 ①传统的调用方式:先调用LoadLibrary来加载dll,再定义函数指针类型,接着调用GetProcAddress获取函数地址.然后通过函数指针调用函数, ...

  4. 第23课 可变参数模板(4)_Optional和Lazy类的实现

    1. optional类的实现 (1)optional的功能 ①optional<T>的内部存储空间可能存储了T类型的值,也可能没有.只有当optional被T初始化之后,这个option ...

  5. C++反射机制:可变参数模板实现C++反射

    1. 概要   本文描述一个通过C++可变参数模板实现C++反射机制的方法.该方法非常实用,在Nebula高性能网络框架中大量应用,实现了非常强大的动态加载动态创建功能.Nebula框架在Github ...

  6. C++ 0x 使用可变参数模板类 实现 C# 的委托机制

    #ifndef _ZTC_DELEGATE_H_ #define _ZTC_DELEGATE_H_ #include <vector> #include <functional> ...

  7. c++11 可变参数模板类

    c++11 可变参数模板类 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #inc ...

  8. c++11 可变参数模板函数

    c++11 可变参数模板函数 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #in ...

  9. C++反射机制:可变参数模板实现C++反射(使用C++11的新特性--可变模版参数,只根据类的名字(字符串)创建类的实例。在Nebula高性能网络框架中大量应用)

    1. 概要   本文描述一个通过C++可变参数模板实现C++反射机制的方法.该方法非常实用,在Nebula高性能网络框架中大量应用,实现了非常强大的动态加载动态创建功能.Nebula框架在码云的仓库地 ...

随机推荐

  1. haxe相关的计划安排

    用多少写多少.先从入门开始,再到怎么写DSL解析器.最后自举(只是做个示范而已 在深入haxe的过程中,多少会跟typescript有交集,这些会边走边总结. 因为只是for example,所以这个 ...

  2. 前端表单验证常用的15个JS正则表达式

    在表单验证中,使用正则表达式来验证正确与否是一个很频繁的操作,本文收集整理了15个常用的javaScript正则表达式,其中包括用户名.密码强度.整数.数字.电子邮件地址(Email).手机号码.身份 ...

  3. unity 中的UGUI 屏蔽鼠标穿透

    void Update() { if(IsTouchedUI()) { Debug.Log("当前触摸在UI上"); } else { Debug.Log("当前没有触摸 ...

  4. K2助力大鹏绿色环保之路

    K2和大鹏结缘可以追溯到2006年,两家践行绿色环保理念的公司一拍即合,开始了十余年的合作之路,在“绿色环保”的路上留下了坚实的脚印. 绿色能源:LNG   广东大鹏液化天然气有限公司成立于2004年 ...

  5. Android : 跟我学Binder --- (3) C程序示例

    目录: Android : 跟我学Binder --- (1) 什么是Binder IPC?为何要使用Binder机制? Android : 跟我学Binder --- (2) AIDL分析及手动实现 ...

  6. python: super原理

    super() 的入门使用 在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能,这时,我们就需要调用父类的方法了,可通过使用 super 来实现,比如: ...

  7. kolla-ansible源码分析

    一.kolla-ansible 源码的目录结构 kolla-ansible是从kolla项目分离出来的一个可交付的项目,kolla-ansible负责部署容器化的openstack各个服务和基础设施组 ...

  8. 18-09-20 关于Xlrd和Xlwt的初步学习

    #一关于利用xlrd 打开Excel 读取数据的简单介绍import xlrd """ #1 xlrd 基础的用法:读取,获取sheet,获取内容,行数,列数def re ...

  9. wpf-X名称空间Attribute

    1.x:class 该属性用于 后台代码与前端xaml代码连接 代码实例如下图 2.x:ClassModifier 该属性用于控制可见级别  public 等 与C#中的可见级别相同 internal ...

  10. c# 如何 使用共用体

    用起来真的方便 转摘如下: C#借助FieldOffset属性实现共用体与强制类型转换 这两天被C#的强制类型转换弄得有点不习惯.事出如此. 在C#中,我打算读二进制文.文件的结构很简单,一连串的紧密 ...