首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >std::function的模板参数是如何工作的?(实现)

std::function的模板参数是如何工作的?(实现)
EN

Stack Overflow用户
提问于 2010-08-21 04:51:23
回答 5查看 26.7K关注 0票数 55

在Bjarne Stroustrup的主页(C++11 FAQ)中:

代码语言:javascript
复制
struct X { int foo(int); };

std::function<int(X*, int)> f;
f = &X::foo; //pointer to member

X x;
int v = f(&x, 5); //call X::foo() for x with 5

它怎麽工作?std::function如何调用foo成员函数

模板参数是int(X*, int)&X::foo是否从成员函数指针转换为非成员函数指针?!

代码语言:javascript
复制
(int(*)(X*, int))&X::foo //casting (int(X::*)(int) to (int(*)(X*, int))

澄清一下:我知道我们不需要强制转换任何指针来使用std:: function,但是我不知道std::function的内部是如何处理成员函数指针和非成员函数指针之间的不兼容性的。我不知道标准是怎么允许我们实现像std::function这样的东西的!

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-08-21 09:27:30

在获得了其他答案和评论的帮助,并阅读了GCC源代码和C++11标准后,我发现可以使用部分模板专门化函数重载来解析函数类型(它的返回类型和参数类型)。

下面是一个简单的(不完整的)示例,用于实现类似于std::function的东西

代码语言:javascript
复制
template<class T> class Function { };

// Parse the function type
template<class Res, class Obj, class... ArgTypes>
class Function<Res (Obj*, ArgTypes...)> {
    union Pointers {
        Res (*func)(Obj*, ArgTypes...);
        Res (Obj::*mem_func)(ArgTypes...);
    };

    typedef Res Callback(Pointers&, Obj&, ArgTypes...);

    Pointers ptrs;
    Callback* callback;

    static Res call_func(Pointers& ptrs, Obj& obj, ArgTypes... args) {
        return (*ptrs.func)(&obj, args...);
    }

    static Res call_mem_func(Pointers& ptrs, Obj& obj, ArgTypes... args) {
        return (obj.*(ptrs.mem_func))(args...);
    }

  public:

    Function() : callback(0) { }

    // Parse the function type
    Function(Res (*func)(Obj*, ArgTypes...)) {
        ptrs.func = func;
        callback = &call_func;
    }

    // Parse the function type
    Function(Res (Obj::*mem_func)(ArgTypes...)) {
        ptrs.mem_func = mem_func;
        callback = &call_mem_func;
    }

    Function(const Function& function) {
        ptrs = function.ptrs;
        callback = function.callback;
    }

    Function& operator=(const Function& function) {
        ptrs = function.ptrs;
        callback = function.callback;
        return *this;
    }

    Res operator()(Obj& obj, ArgTypes... args) {
        if(callback == 0) throw 0; // throw an exception
        return (*callback)(ptrs, obj, args...);
    }
};

用法:

代码语言:javascript
复制
#include <iostream>

struct Funny {
    void print(int i) {
        std::cout << "void (Funny::*)(int): " << i << std::endl;
    }
};

void print(Funny* funny, int i) {
    std::cout << "void (*)(Funny*, int): " << i << std::endl;
}

int main(int argc, char** argv) {
    Funny funny;
    Function<void(Funny*, int)> wmw;

    wmw = &Funny::print; // void (Funny::*)(int)
    wmw(funny, 10); // void (Funny::*)(int)

    wmw = &print; // void (*)(Funny*, int)
    wmw(funny, 8); // void (*)(Funny*, int)

    return 0;
}
票数 35
EN

Stack Overflow用户

发布于 2010-08-21 05:16:54

它是如何做到的(我相信)还没有定义(但我这里没有标准的副本)。

但是考虑到需要涵盖的所有不同的可能性,我有一种感觉,破译它如何工作的确切定义将非常困难:所以我不打算尝试。

但我想你会想知道函数器是如何工作的,而且它们相对简单。这里有一个简单的例子。

函数式:

这些对象的行为类似于函数。

它们在模板代码中非常有用,因为它们通常允许您互换使用对象或函数。不过,函数器的伟大之处在于,它们可以保持状态(一种穷人的闭包)。

代码语言:javascript
复制
struct X
{
     int operator()(int x) { return doStuff(x+1);}
     int doStuff(int x)    { return x+1;}
};

X   x;  // You can now use x like a function
int  a = x(5);

您可以利用functor保持状态的事实来保持参数、对象或指向成员方法的指针(或它们的任意组合)。

代码语言:javascript
复制
struct Y // Hold a member function pointer
{
    int (X::*member)(int x);
    int operator(X* obj, int param) { return (obj->*member)(param);}
};
X  x;
Y  y;
y.member = &X::doStuff;
int a = y(&x,5);

或者甚至更进一步,绑定参数。所以现在您需要提供的只是其中一个参数。

代码语言:javascript
复制
struct Z
{
    int (X::*member)(int x);
    int  param;
    Z(int (X::*m)(int), int p) : member(m), param(p) {}

    int operator()(X* obj)  { return (obj->*member)(param);}
    int operator()(X& obj)  { return (obj.*member)(param);}
};

Z z(&X::doStuff,5);

X x;
int a = z(x);
票数 4
EN

Stack Overflow用户

发布于 2018-11-12 13:16:39

回答标题中的问题。std::function使用的参数是一个很好的技巧,可以将多个类型参数作为一个模板参数进行传递。这些参数是函数的参数类型和返回类型。

事实证明,std::function试图擦除一个通用函数器的类型,但这只是巧合。

事实上,曾几何时,有些编译器不会接受这样的技巧,而boost::function的前身有一种可移植的语法,所有参数都可以通过它单独传递:

首选语法

boost::function sum_avg;

可移植的语法

boost::function4 sum_avg;

https://www.boost.org/doc/libs/1_68_0/doc/html/function/tutorial.html#id-1.3.16.5.4

这就是std::function的模板参数是如何工作的,最后,这只是一个技巧,让很多参数看起来像一个函数调用。指向该类型函数的函数指针不一定包含在类中。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3534812

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档