std :: function的模板参数如何工作? (实施) [英] How does the template parameter of std::function work? (implementation)
问题描述
在 的主页( 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 union
s, 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屋!