std :: function的模板参数如何工作? (实施) [英] How does the template parameter of std::function work? (implementation)

查看:907
本文介绍了std :: function的模板参数如何工作? (实施)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

的主页( C ++ 11 FAQ ):

  struct X {int foo(int); }; 

std :: function< int(X *,int)> F;
f =& X :: foo; //指向成员的指针

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

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



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

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






澄清:我知道我们不需要使用任何指针来使用 std :: function ,但是我不知道 std :: function 的内部如何处理成员函数指针非成员函数指针之间的不兼容性。 / em>。我不知道标准如何允许我们实现像 std :: function

解决方案<



我发现了标准的第14.8.2.5-21节的一个很好的例子:

  template< class> struct X {}; 
template< class R,class ... ArgTypes> struct X template< class ... Types> struct Y {};
template< class T,class ... Types> struct Y template< class ... Types> int f(void(*)(Types ...));
void g(int,float);
//使用主模板
X< int> x1;
//使用部分特化; argTypes包含float,double
X< int(int,float,double)> x2;
//使用主模板
X< int(float,int)> x3;
//使用主模板;类型为空
Y<> y1;
//使用部分特化; T是int&类型包含float,double
Y< int& amp; float& y2;
//使用主模板;类型包含int,float,double
Y< int,float,double> y3;
// OK;类型包含int,float
int fv = f(g);

它说,使用模板专门化,我们可以解析函数类型的模板参数(awesome)!下面是关于std :: function如何工作的脏/简单示例:

  template< class T& struct Function {}; 

template< class T,class Obj,class ... Args>
struct Function< T(Obj *,Args ...)> //解析函数类型
{
enum FuncType
{
FuncTypeFunc,
FuncTypeMemFunc
};
union FuncPtr
{
T(* func)(Obj *,Args ...);
T(Obj :: * mem_func)(Args ...);
};

FuncType m_flag;
FuncPtr m_func_ptr;

函数(T(* func)(Obj *,Args ...))// void(*)(Funny *,int,int)
{
m_flag = FuncTypeFunc;
m_func_ptr.func = func;
}
函数(T(Obj :: * mem_func)(Args ...))// void(Funny :: *)(int,int)
{
m_flag = FuncTypeMemFunc;
m_func_ptr.mem_func = mem_func;
}

void play(Obj * obj,Args ... args)
{
switch(m_flag)
{
case FuncTypeFunc :
(* m_func_ptr.func)(obj,args ...);
break;
case FuncTypeMemFunc:
(obj-> * m_func_ptr.mem_func)(args ...);
break;
}
}
};

用法:

 code> #include< iostream> 

struct有趣的
{
void done(int i,int j)
{
std :: cout< 成员函数:< i<< ,< j<< std :: endl;
}
};

void done(Funny * funny,int i,int j)
{
std :: cout< 功能:< i<< ,< j<< std :: endl;
}

int main(int argc,char ** argv)
{
有趣的;
Function< void(Funny *,int,int)> f =& Funny :: done; // void(Funny :: *)(int,int)
函数< void(Funny *,int,int) g =& done; // void(*)(Funny *,int,int)
f.play(& funny,5,10); // void(Funny :: *)(int,int)
g.play(& funny,5,10); // void(*)(Funny *,int,int)
return 0;
}

编辑:感谢Tomek 关于 union ,上述示例被更改为在一个(非两个)变量中保存成员/非成员函数指针。






编辑:马丁约翰是对的, switch语句在上述示例中不是一个好主意,所以我改变了示例完全工作更好:

  template< class T& class Function {}; 

template< class Res,class Obj,class ... ArgTypes>
class Function< Res(Obj *,ArgTypes ...)> //解析函数类型
{
union Pointers //用于保存不同类型的指针的联合
{
Res(* func)(Obj *,ArgTypes ...) ; // void(*)(Funny *,int)
Res(Obj :: * mem_func)(ArgTypes ...); // void(Funny :: *)(int)
};
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 .. 。); // void(*)(Funny *,int)
}
static Res call_mem_func(Pointers& ptrs,Obj& obj,ArgTypes ... args)
{
return obj。*(ptrs.mem_func))(args ...); // void(Funny :: *)(int)
}

public:

Function():callback (Res(* func)(Obj *,ArgTypes ...))// void(*)(Funny *,int)
{
ptrs.func = func;
callback =& call_func;
}
功能(Res(Obj :: * mem_func)(ArgTypes ...))// void(Funny :: *)(int)
{
ptrs.mem_func = mem_func;
callback =& call_mem_func;
}
函数(const Function& function)
{
ptrs = function.ptrs;
callback = function.callback;
}
功能& operator =(const Function& function)
{
ptrs = function.ptrs;
callback = function.callback;
return * this;
}
Res操作符()(Obj& obj,ArgTypes ... args)
{
if(callback == 0)throw 0; // throw a exception
return(* callback)(ptrs,obj,args ...);
}
};

用法:

 code> #include< iostream> 

struct有趣的
{
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)
{
有趣的;
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;
}


In Bjarne Stroustrup's home page (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

How does it work? How does std::function call a foo member function?

The template parameter is int(X*, int), is &X::foo converted from the member function pointer to a non-member function pointer?!

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


To clarify: I know that we don't need to cast any pointer to use std::function, but I don't know how the internals of std::function handle this incompatibility between a member function pointer and a non-member function pointer. I don't know how the standard allows us to implement something like std::function!

解决方案

Thanks for all answers.

I found a good example from section 14.8.2.5-21 of the standard:

template<class> struct X { };
template<class R, class ... ArgTypes> struct X<R(int, ArgTypes ...)> { };
template<class ... Types> struct Y { };
template<class T, class ... Types> struct Y<T, Types& ...> { };
template<class ... Types> int f(void (*)(Types ...));
void g(int, float);
// uses primary template
X<int> x1;
// uses partial specialization; ArgTypes contains float, double
X<int(int, float, double)> x2;
// uses primary template
X<int(float, int)> x3;
// use primary template; Types is empty
Y<> y1;
// uses partial specialization; T is int&, Types contains float, double
Y<int&, float&, double&> y2;
// uses primary template; Types contains int, float, double
Y<int, float, double> y3;
// OK; Types contains int, float
int fv = f(g);

It says that with template specialization, we can parse template parameters of a function type (awesome)! The following is a dirty/simple example about how std::function can work:

template<class T> struct Function { };

template<class T, class Obj, class... Args>
struct Function<T(Obj*, Args...)> // Parsing the function type
{
    enum FuncType
    {
        FuncTypeFunc,
        FuncTypeMemFunc
    };
    union FuncPtr
    {
        T(*func)(Obj*, Args...);
        T(Obj::*mem_func)(Args...);
    };

    FuncType m_flag;
    FuncPtr m_func_ptr;

    Function(T(*func)(Obj*, Args...)) // void(*)(Funny*, int, int)
    {
        m_flag = FuncTypeFunc;
        m_func_ptr.func = func;
    }
    Function(T(Obj::*mem_func)(Args...)) // void(Funny::*)(int, int)
    {
        m_flag = FuncTypeMemFunc;
        m_func_ptr.mem_func = mem_func;
    }

    void play(Obj* obj, Args... args)
    {
        switch(m_flag)
        {
          case FuncTypeFunc:
            (*m_func_ptr.func)(obj, args...);
            break;
          case FuncTypeMemFunc:
            (obj->*m_func_ptr.mem_func)(args...);
            break;
        }
    }
};

Usage:

#include <iostream>

struct Funny
{
    void done(int i, int j)
    {
        std::cout << "Member Function: " << i << ", " << j << std::endl;
    }
};

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

int main(int argc, char** argv)
{
    Funny funny;
    Function<void(Funny*, int, int)> f = &Funny::done; // void(Funny::*)(int, int)
    Function<void(Funny*, int, int)> g = &done; // void(*)(Funny*, int, int)
    f.play(&funny, 5, 10); // void(Funny::*)(int, int)
    g.play(&funny, 5, 10); // void(*)(Funny*, int, int)
    return 0;
}

Edit: Thanks to Tomek for his good hint about unions, the above example is changed to hold the member/non-member function pointer in one (not two) variable.


Edit: Martin York is right, the switch statement wasn't a good idea in the above example, so i changed the example completely to work better:

template<class T> class Function { };

template<class Res, class Obj, class... ArgTypes>
class Function<Res (Obj*, ArgTypes...)> // Parsing the function type
{
    union Pointers // An union to hold different kind of pointers
    {
        Res (*func)(Obj*, ArgTypes...); // void (*)(Funny*, int)
        Res (Obj::*mem_func)(ArgTypes...); // void (Funny::*)(int)
    };
    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...); // void (*)(Funny*, int)
    }
    static Res call_mem_func(Pointers& ptrs, Obj& obj, ArgTypes... args)
    {
        return (obj.*(ptrs.mem_func))(args...); // void (Funny::*)(int)
    }

  public:

    Function() : callback(0) { }
    Function(Res (*func)(Obj*, ArgTypes...)) // void (*)(Funny*, int)
    {
        ptrs.func = func;
        callback = &call_func;
    }
    Function(Res (Obj::*mem_func)(ArgTypes...)) // void (Funny::*)(int)
    {
        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...);
    }
};

Usage:

#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;
}

这篇关于std :: function的模板参数如何工作? (实施)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆