惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Fortinet All Blogs
博客园 - 三生石上(FineUI控件)
小众软件
小众软件
人人都是产品经理
人人都是产品经理
V
Visual Studio Blog
Last Week in AI
Last Week in AI
V
V2EX
博客园_首页
IT之家
IT之家
Jina AI
Jina AI
博客园 - 叶小钗
The Cloudflare Blog
T
Tailwind CSS Blog
腾讯CDC
B
Blog
D
Docker
L
LangChain Blog
博客园 - 司徒正美
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
美团技术团队
Apple Machine Learning Research
Apple Machine Learning Research
爱范儿
爱范儿
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
GbyAI
GbyAI

博客园 - shootingstars

硬件相关概念 C的可变参数 C++概念网摘 Mifare 串行读取协议 韦根协议 学习C的可变参数 关于汇编程序调用各种C函数的例子 如何移植Java的类中的super到C++代码中 编译原理学习 关于标准库中的ptr_fun/binary_function/bind1st/bind2nd 使用python编写每日构建工具 boost::regex学习(5) - shootingstars - 博客园 boost::regex学习(4) - shootingstars - 博客园 boost::regex学习(3) boost::regex学习(2) 《世界大战》《变形金刚》观后感 boost::regex学习(1) boost::algorithm学习 五种迭代器
我的Function
shootingstars · 2010-01-11 · via 博客园 - shootingstars

我们有些时候需要存储一些函数以备后用,最常用的就是C中的Callback。。。
但是到了C++年代,函数都放到了类中,想要Callback就有些复杂了。Boost::function封装了一个模版库,它可以接受静态函数,普通函数以及仿函数,为了了解它的原理,我自己试图写一个简单的类。。。

我们先看boost中function的使用
boost::function<int(int)> func; // 能接受int(int)型的函数或仿函数
在模版参数中我们看到int(int) ,这个可能一般用户感到陌生,其实它是一个函数类型,表示返回值是int,并且有一个参数是int的函数类型。
一直以来令我感到困惑的是:int(int)仅仅是一个类型,一般而言我们如果需要用模版接受这个参数的话,可以这么用
template <class F>
class Function
问题是这样的话,所有的返回值和参数(个数)信息会全部丢失,这样在Function中的operator()就无法写出合适的调用形式。

一种方式是不用此种函数类型,而用多个模版参数。如
template <class Ret, class Param1>
class Function
此时很容易得到函数的返回值和参数(并且有些Function/Delegate库中确实是这么用的,Boost的可移植类型也是这么干的),但是这么做的话,用户可能看着不习惯。
我们来看看boost是如何做到用一个模板参数同时也可以得到函数类型的返回值和参数个数信息的。
答案就是模板偏特化
在boost中有一个根本未起作用的Function类
template<
typename Signature
>
class function;
但是它有多个偏特化的版本,其中一个如下:
template<typename R,typename P1>
class function<R(P1)>
这个模版偏特化了上述的模版,并且区分出了返回值和参数。嗯,现在我们可以做一个简单的Function看看好不好使

template <typename R, typename P1>
class Function<R(P1)>
{
    typedef R (
*fun)(P1);
public:
    Function()
    {
        m_function 
= NULL;
    }

    Function(fun f)
    {
        m_function 

= f;
    }
    
    R 
operator()(P1 p1)
    {
        
return m_function(p1);
    }
void operator=(fun f)
    {
        m_function 
= f;
    }
private:
    fun m_function;
};
int PrintInt(int i)
{
    printf(
"PrintInt=%d\n",i);
    
return i;
}

Function

<int(int)> fun(PrintInt);int main(int argc, char* argv[])
{
    fun(
20);
    
return 0;
}

代码

template<
typename Signature
>
class Function;

template 

<typename R, typename P1>
class Function<R(P1)>
{
    typedef R (
*fun)(P1);
public:
    Function()
    {
        m_function 
= NULL;
    }

    Function(fun f)
    {
        m_function 

= f;
    }
    
    R 
operator()(P1 p1)
    {
        
return m_function(p1);
    }
void operator=(fun f)
    {
        m_function 
= f;
    }
private:
    fun m_function;
};
int PrintInt(int i)
{
    printf(
"PrintInt=%d\n",i);
    
return i;
}

Function

<int(int)> fun(PrintInt);int main(int argc, char* argv[])
{
    fun(
20);
    
return 1;
}

继续,我们想包装一个类的成员变量,boost推荐的是如下调用方式:

boost::function<int (X*, int)> f;

表示此funtion接受一个类名为X,返回值为int,参数为int的函数。。。嗯,怎么看怎么不爽。。。为啥不用类的成员变量的表达方式呢--- int (FunClass::*)(int) ,也许是很多编译器不支持?

我们看看目前主流C++编译器是否支持此种类型。(vc2008和g++ 4.1.3)偏特化如下代码:

代码

template<
typename Signature
>
class Function;

template 

<typename R, typename P1, class T>
class Function<R (T::*)(P1)>
{
    typedef R (T::
*fun)(P1);
public:

    Function(T 

&t, fun f) : m_class(t)
    {
        m_function 
= f;
    }
    
    R 
operator()(P1 p1)
    {
        
return (m_class.*m_function)(p1);
    }
private:
    T   
&m_class;
    fun       m_function;
};
class FunClass
{
public:
    
int fun(int i)
    {
        printf(
"FunClass fun %d\n",i);
        
return i;
    }
};
int main(int argc, char* argv[])
{
    FunClass funclass;
    Function
<int (FunClass::*)(int)> fun(funclass, &FunClass::fun);
    fun(
123);
    
return 1;
}

哈哈,编译器老老实实通过了,结果也对。