我在之前的随笔中介绍了function如何保存参数,如何实现调用相关知识。对于一个函数对象或者函数指针来说,应该很容易理解。不过对于如何在function中保存类的成员函数,这个还是值得一说的。

还是按照之前的方式,通过boost的type_index,我们可以比较容易的知道function的父类是_Func_class。

这里先看一段代码:

    template<class _Fx,
class _Inv_res = typename _Mybase::template _Result_of_invoking_t<_Fx&>,
class = typename _Mybase::template _Enable_if_returnable_t<_Inv_res> >
function(_Fx _Func)
{ // construct wrapper holding copy of _Func
this->_Reset(_STD move(_Func));
}

这个是function的一个构造函数,其中的_Inv_res是这个构造函数能够使用的条件,条件的内容是_Mybase::_Result_of_invoking_t<_Fx&>可以获得一个类型。

现在我们查看_Result_of_invoking_t定义的位置:

protected:
template<class _Fx>
using _Result_of_invoking_t = result_of_t<_Fx(_Types...)>;

上面是在_Func_class中的定义。下面给出类result_of_t的定义。

template<class _Ty>
using result_of_t = typename result_of<_Ty>::type; template<class _Void,
class... _Types>
struct _Result_of
{ // selected when _Fty isn't callable with _Args
}; template<class... _Types>
struct _Result_of<
void_t<
_Unique_tag_result_of, // TRANSITION, C1XX
decltype(_STD invoke(_STD declval<_Types>()...))>,
_Types...>
{ // selected when _Fty is callable with _Args
typedef decltype(_STD invoke(_STD declval<_Types>()...)) type;
}; template<class _Fty>
struct result_of
{ // explain usage
static_assert(_Always_false<_Fty>::value,
"result_of<CallableType> is invalid; use "
"result_of<CallableType(zero or more argument types)> instead.");
}; #define _RESULT_OF(CALL_OPT, X1, X2) \
template<class _Fty, \
class... _Args> \
struct result_of<_Fty CALL_OPT (_Args...)> \
: _Result_of<void, _Fty, _Args...> \
{ /* template to determine result of call operation */ \
};

由上述代码可知,result_of的实现依赖于std::invoke函数的实现。

我们再查看一下function函数的调用路径:

    _Ret operator()(_Types... _Args) const
{ // call through stored object
if (_Empty())
_Xbad_function_call();
return (_Getimpl()->_Do_call(_STD forward<_Types>(_Args)...));
}

上述是_Func_class的调用函数。

    virtual _Rx _Do_call(_Types&&... _Args)
{ // call wrapped function
return (_Invoke_ret(_Forced<_Rx>(), _Callee(),
_STD forward<_Types>(_Args)...));
}

这个是_Func_impl的调用,也就是上面_Getimpl()->_Do_call的实现函数。下面,我们再查看一下_Invoke_ret的实现:

template<class _Cv_void,
class... _Valtys> inline
void _Invoke_ret(_Forced<_Cv_void, true>, _Valtys&&... _Vals)
{ // INVOKE, "implicitly" converted to void
_STD invoke(_STD forward<_Valtys>(_Vals)...);
} template<class _Rx,
class... _Valtys> inline
_Rx _Invoke_ret(_Forced<_Rx, false>, _Valtys&&... _Vals)
{ // INVOKE, implicitly converted to _Rx
return (_STD invoke(_STD forward<_Valtys>(_Vals)...));
} template<class... _Valtys> inline
auto _Invoke_ret(_Forced<_Unforced, false>, _Valtys&&... _Vals)
-> decltype(_STD invoke(_STD forward<_Valtys>(_Vals)...))
{ // INVOKE, unchanged
return (_STD invoke(_STD forward<_Valtys>(_Vals)...));
}

由上面代码可见,无一例外,function的判断和实现都依赖于std::invoke的实现。那么std::invoke是如何实现的呢?

template<class _Callable,
class... _Types> inline
auto invoke(_Callable&& _Obj, _Types&&... _Args)
-> decltype(_Invoker<_Callable, _Types...>::_Call(
_STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...))
{ // INVOKE a callable object
return (_Invoker<_Callable, _Types...>::_Call(
_STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...));
}

在VS2015中,invoke的实现代码如上,可见invoke的实现依赖于_Invoker类。下面,我们查看一下_Invoker的实现:

template<class _Callable,
class... _Types>
struct _Invoker; template<class _Callable>
struct _Invoker<_Callable>
: _Invoker_functor
{ // zero arguments
}; template<class _Callable,
class _Ty1,
class... _Types2>
struct _Invoker<_Callable, _Ty1, _Types2...>
: _Invoker1<_Callable, _Ty1>
{ // one or more arguments
};

可见,我们需要继续查看_Invoker1的实现:

template<class _Callable,
class _Ty1,
class _Decayed = typename decay<_Callable>::type,
bool _Is_pmf = is_member_function_pointer<_Decayed>::value,
bool _Is_pmd = is_member_object_pointer<_Decayed>::value>
struct _Invoker1; template<class _Callable,
class _Ty1,
class _Decayed>
struct _Invoker1<_Callable, _Ty1, _Decayed, true, false>
: _If<is_base_of<
typename _Is_memfunptr<_Decayed>::_Class_type,
typename decay<_Ty1>::type>::value,
_Invoker_pmf_object,
_Invoker_pmf_pointer>::type
{ // pointer to member function
}; template<class _Callable,
class _Ty1,
class _Decayed>
struct _Invoker1<_Callable, _Ty1, _Decayed, false, true>
: _If<is_base_of<
typename _Is_member_object_pointer<_Decayed>::_Class_type,
typename decay<_Ty1>::type>::value,
_Invoker_pmd_object,
_Invoker_pmd_pointer>::type
{ // pointer to member data
}; template<class _Callable,
class _Ty1,
class _Decayed>
struct _Invoker1<_Callable, _Ty1, _Decayed, false, false>
: _Invoker_functor
{ // function object
};

以及实现_Invoker1的底层类:

struct _Invoker_pmf_object
{ // INVOKE a pointer to member function on an object
template <class _Decayed, class _Ty1, class... _Types2>
static auto _Call(_Decayed _Pmf, _Ty1&& _Arg1, _Types2&&... _Args)
->decltype((std::forward<_Ty1>(_Arg1).*_Pmf)(
std::forward<_Types2>(_Args2)...))
{ // INVOKE a pointer to member function on an object
return ((_STD forward<_Ty1>(_Arg1).*_Pmf)(
std::forward<_Types2>(_Args2)...
));
}
}; struct _Invoker_pmf_pointer
{ // INVOKE a pointer to member function on a [smart] pointer
template <class _Decayed, class _Ty1, class... _Types2>
static auto _Call(_Decayed _Pmf, _Ty1&& _Arg1, _Types2&&... Args2)
->decltype(((*std::forward<_Ty1>(_Arg1)).*_Pmf)(
std::forward<_Types2>(_Arg2)...))
{ // INVOKE a pointer to member function on a [smart] pointer
return (((*std::forward<_Ty1>(_Arg1)).*_Pmf)(
std::forward<_Types2>(_Arg2)...));
}
}; struct _Invoker_pmd_object
{ // INVOKE a pointer to member data on an object
template<class _Decayed, class _Ty1>
static auto _Call(_Decayed _Pmd, _Ty1&& _Arg1)
->decltype(std::forward<_Ty1>(_Arg1).*_Pmd)
{ // INVOKE a pointer to member data on a [smart] pointer
return (std::forward<_Ty1>(_Arg1).*_Pmd);
} }; struct _Invoker_pmd_pointer
{ // INVOKE a pointer to member data on a [smart] pointer
template <class _Decayed, class _Ty1>
static auto _Call(_Decayed _Pmd, _Ty1&& _Arg1)
->decltype((*std::forward<_Ty1>(_Arg1)).*_Pmd)
{ // INVOKE a pointer to member data on a [smart] pointer
return ((*std::forward<_Ty1>(_Arg1)).*_Pmd);
}
}; struct _Invoker_functor
{ // INVOKE a function object
template <class _Callable, class... _Types>
static auto _Call(_Callable&& _Obj, _Types&&... _Args)
->decltype(std::forward<_Callable>(_Obj)(
std::forward<_Types>(_Args)...))
{ // INVOKE a function object
return (std::forward<_Callable>(_Obj)(
std::forward<_Types>(_Args)...));
}
};

实现的过程,主要在于:bool _Is_pmf = is_member_function_pointer<_Decayed>::value和bool _Is_pmd = is_member_object_pointer<_Decayed>::value>两个判断语句,通过这个来实现SFINAE的语义,从而实现针对类型的特例化。为了说明上面两个判断才是重点,输入如下代码:

class A
{
public:
A(){} void printA() const
{
std::cout << "printA" << std::endl;
}
}; void printB(A a)
{
std::cout << "printB" << std::endl;
} int main()
{
std::_Invoker_pmf_object::_Call(&A::printA, A());
std::_Invoker_pmf_pointer::_Call(&A::printA, &A());
std::_Invoker_functor::_Call(printB, A()); return ;
}

查看打印结果。由于_Invoker_pmf_object,_Invoker_pmf_pointer和_Invoker_functor的实现本来很简单,所以invoke调用的重点在于上述判断语句。这里就解释到此,时间仓促,希望见谅。

VC的function类说明 -- 继续的更多相关文章

  1. VC中function函数解析

    C++标准库是日常应用中非常重要的库,我们会用到C++标准库的很多组件,C++标准库的作用,不单单是一种可以很方便使用的组件,也是我们学习很多实现技巧的重要宝库.我一直对C++很多组件的实现拥有比较强 ...

  2. VC++导入导出类

    一.导出类 VC++中导出类很简单,下面列出了两个等价的方法: 方法1: class __declspec(dllexport) CTest { public: int        m_nValue ...

  3. VC++中的类的内存分布(上)

    0.序 目前正在学习C++中,对于C++的类及其类的实现原理也挺感兴趣.于是打算通过观察类在内存中的分布更好地理解类的实现.因为其实类的分布是由编译器决定的,而本次试验使用的编译器为VS2015 RC ...

  4. VC++中的类的内存分布(上)(通过强制转换,观察地址,以及地址里的值来判断)

    0.序 目前正在学习C++中,对于C++的类及其类的实现原理也挺感兴趣.于是打算通过观察类在内存中的分布更好地理解类的实现.因为其实类的分布是由编译器决定的,而本次试验使用的编译器为VS2015 RC ...

  5. JavaScript学习总结(十五)——Function类

    在JavaScript中,函数其实是对象,每个函数都是Function类的实例,既然函数对象,那么就具有自己的属性和方法,因此,函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定. 一.函数的 ...

  6. js面向对象设计之function类

    本文仅探讨如何合理的使用 function 在 javascript中实现一个面向对象设计的类.总所周知,javascript 并不能实现一个真正意义上的类,比如 protect 比如 函数重载.下面 ...

  7. JavaScript语言精粹--Function,类,this,对象

    1.类与对象 在JS中,创建对象(Create Object)并不完全是我们时常说的创建类对象,JS中的对象强调的是一种复合类型,JS中创建对象及对对象的访问是极其灵活的. JS对象是一种复合类型,它 ...

  8. 【C++对象模型】使用gcc、clang和VC++显示C++类的内存布局

    引言 各种C++实现对C++类/对象的内存布局可能有所不同,包括数据成员的顺序.虚函数表(virtual table: vtbl)的结构.继承关系的处理等.了解C++类/对象的布局,对于理解C++各种 ...

  9. 钩子函数 Function类

    Function 为 com.google.common.base包下接口类: public interface Function<F, T> { @Nullable T apply(@N ...

随机推荐

  1. hdu2461 Rectangles 线段树--扫描线

    You are developing a software for painting rectangles on the screen. The software supports drawing s ...

  2. 把目录C:\Python34\PCI_Code\chapter2\加到系统路径中

    >>> import sys >>> sys.path.append("C:\Python34\PCI_Code\chapter2")

  3. 【BZOJ2427】【HAOI2010】软件安装

    无力吐槽…… 原题: 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最 ...

  4. centos7之zabbix入门(一)

    初始化状态如下 首先按照下面的步骤进行,主机名和可见名可以自己起,dns那里最好也填一下,其它默认就可以了 点击确认后,自动跳转到以下页面 可以看到zbx那里没有亮起来,说明还没有配置成功,接下来点击 ...

  5. sqler sql 转rest api 的docker image

    最新sqler 又发布了一个版本,同时官方文档也更新,对于数据库的连接有了详细的说明 Dockerfile 为了方便以及减少大小,使用多阶段构建,同时都通过环境变量运行 FROM alpine:lat ...

  6. Explicit

    Prefixing the explicit keyword to the constructor prevents the compiler from using that constructor ...

  7. 性能测试之mysql监控、优化

    我们在做性能测试的目的是什么,就是要测出一个系统的瓶颈在哪里,到底是哪里影响了我们系统的性能,找到问题,然后解决它.当然一个系统由很多东西一起组合到一起,应用程序.数据库.服务器.中中间件等等很多东西 ...

  8. 99乘法表的正反写 (python的写法)

    # 正写 j = 0 k = 0 while j < 10: j+=1 while k <10: k+=1 if j>k: k = 0 break else: print('{}*{ ...

  9. oracle之 单实例监听修改端口

    Oracle 单一主机多个实例多个监听器配置要点   1. 一台服务器主机, 有多个实例, 如: TSDB/ORCL; 又需要配置多个监听器 2. 需要指定不同的LISTENER端口   3.pmon ...

  10. docker 学习资料

    docker 学习资料 学习资料 网址 Docker 教程(菜鸟教程) http://www.runoob.com/docker/docker-tutorial.html