代码之家  ›  专栏  ›  技术社区  ›  Sadeq

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

  •  53
  • Sadeq  · 技术社区  · 14 年前

    本贾尼·斯特劳斯特卢普 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
    

    它是如何工作的?你怎么知道的 std::函数 foo成员函数 ?

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

    (int(*)(X*, int))&X::foo //casting (int(X::*)(int) to (int(*)(X*, int))
    

    澄清一下:我知道我们不需要使用任何指针 但我不知道 std::函数 成员函数指针 非成员函数指针 . 我不知道标准是如何允许我们实现 std::函数

    5 回复  |  直到 9 年前
        1
  •  35
  •   Sadeq    6 年前

    返回类型 以及它的 参数类型 )通过使用 函数重载

    下面是一个简单(但不完整)的示例来实现 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...);
        }
    };
    

    #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;
    }
    
        2
  •  4
  •   Community Mr_and_Mrs_D    4 年前

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

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

    函子:

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

    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);
    

    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);
    

    或者更进一步绑定参数。所以现在只需要提供一个参数。

    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);
    
        3
  •  3
  •   alfC    5 年前

    回答题目中的问题。参数 std::function 将多个类型参数作为单个模板参数传递是一个很好的技巧。这些参数是函数的参数类型和返回类型。

    事实证明 std::函数 试图删除一般函子,但那只是巧合。

    事实上,很久以前有一些编译器不接受这样的技巧和错误 boost::function 便携式的

    首选语法

    boost::function<void(int*, int, int&, float&)> sum_avg;
    

    可移植语法

    boost::function4<void, int*, int, int&, float&> sum_avg;
    

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

    这就是 std::函数 工作,最后它只是一个技巧,使许多参数看起来像一个函数调用。指向该类型函数的函数指针是 参与课堂。

        4
  •  2
  •   Puppy    14 年前

        5
  •  2
  •   Tomek    14 年前

    g++似乎有一个并集,它可以保留函数指针、成员指针或可能指向函子的空指针。添加适当标记哪个联合成员是有效的重载,并将其重载到一个soup中,然后它就可以工作了。。。