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

M. *_* E. 53 c++ templates function-pointers function-object c++11

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

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
Run Code Online (Sandbox Code Playgroud)

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

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

(int(*)(X*, int))&X::foo //casting (int(X::*)(int) to (int(*)(X*, int))
Run Code Online (Sandbox Code Playgroud)

澄清:我知道我们不需要使用任何指针来使用std :: function,但我不知道std :: function的内部如何处理成员函数指针非成员函数之间的这种不兼容性指针.我不知道标准如何允许我们实现像std :: function这样的东西!

M. *_* E. 34

在从其他答案和评论中获得帮助,并阅读GCC源代码和C++ 11标准之后,我发现可以通过使用部分模板特化函数重载来解析函数类型(其返回类型及其参数类型).

以下是一个简单(且不完整)的示例,用于实现以下内容std::function:

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...);
    }
};
Run Code Online (Sandbox Code Playgroud)

用法:

#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;
}
Run Code Online (Sandbox Code Playgroud)

  • 人们不愿意认为这段代码中有一个switch语句. (3认同)
  • 除了函数指针和成员函数指针之外,`std :: function`还接受函数对象 (3认同)