C++ std::function 的模板参数如何工作?(执行)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3534812/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does the template parameter of std::function work? (implementation)
提问by M. Sadeq H. E.
In Bjarne Stroustrup's home page (C++11 FAQ):
在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
How does it work? How does std::functioncall a foo member function?
它是如何工作的?std::function如何调用foo 成员函数?
The template parameter is int(X*, int)
, is &X::foo
converted from the member function pointerto a non-member function pointer?!
模板参数int(X*, int)
,是&X::foo
从转换成员函数指针到一个非成员函数指针?!
(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::functionhandle this incompatibility between a member function pointerand a non-member function pointer. I don't know how the standard allows us to implement something like std::function!
澄清:我知道我们不需要强制转换任何指针来使用std::function,但我不知道std::function的内部如何处理成员函数指针和非成员函数之间的这种不兼容性指针。我不知道标准如何允许我们实现std::function 之类的东西!
采纳答案by M. Sadeq H. E.
After getting help from other answers and comments, and reading GCC source code and C++11 standard, I found that it is possible to parse a function type (its return typeand its argument types) by using partial template specializationand function overloading.
在从其他答案和评论中获得帮助,并阅读 GCC 源代码和 C++11 标准后,我发现可以通过使用部分模板特化和 函数重载来解析函数类型(其返回类型及其参数类型)。
The following is a simple (and incomplete) example to implement something like std::function
:
以下是一个简单(且不完整)的示例,用于实现以下内容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...);
}
};
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;
}
回答by Martin York
How it does it (I believe) is left undefined (but I don't have a copy of the standard here).
它是如何做的(我相信)是未定义的(但我这里没有标准的副本)。
But given all the different possibilities that need to be covered I have the feeling that deciphering the exact definition of how it works would be really hard: So I am not going to try.
但是考虑到需要涵盖的所有不同可能性,我觉得破译它如何工作的确切定义真的很难:所以我不打算尝试。
But I think you would like to know how functors work and they are relatively simple. So here is a quick example.
但我想你想知道函子是如何工作的,而且它们相对简单。所以这是一个简单的例子。
Functors:
函子:
These are objects that act like functions.
They are very useful in template code as they often allow you to use objects or functions interchangeably. The great thing about functors though is that they can hold state (a sort of poor man's closure).
这些是行为类似于函数的对象。
它们在模板代码中非常有用,因为它们通常允许您互换使用对象或函数。不过,函子的伟大之处在于它们可以保持状态(一种穷人的闭包)。
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);
You can use the fact that functor hold state to hold things like parameters or the objects or the pointer to member methods (or any combination thereof).
您可以使用函子保持状态的事实来保存诸如参数或对象或指向成员方法的指针(或它们的任何组合)之类的东西。
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);
Or even go further and bind parameters. So now all you need to provide is one of the parameters.
甚至更进一步绑定参数。所以现在您需要提供的只是参数之一。
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);
回答by Tomek
g++ seems to have an union which may keep either function pointer, member pointer or void pointer which probably points to a functor. Add overloads which appropriately flag which union member is valid and heavy casting to a soup and then it works...
g++ 似乎有一个联合,它可以保留函数指针、成员指针或可能指向函子的空指针。添加重载,适当地标记哪个联合成员有效并且重铸到汤中,然后它工作......
回答by Puppy
They're not function pointers. That's what std::function exists for. It wraps whatever callable types you give it. You should check out boost::bind- it's often used to make member function pointers callable as (this, args).
它们不是函数指针。这就是 std::function 存在的目的。它包装了您提供的任何可调用类型。您应该查看 boost::bind-它通常用于使成员函数指针可调用为 (this, args)。
回答by alfC
To answer the question in the title. The parameter that std::function
uses is a nice trick to pass many type parameters as a single template parameter. Those arguments being the argument types and the return type of a function.
回答标题中的问题。使用的参数std::function
是一个很好的技巧,可以将许多类型参数作为单个模板参数传递。这些参数是函数的参数类型和返回类型。
It turns out that std::function
tries to type-erase a general functor but that is just coincidence.
事实证明,它std::function
试图对通用函子进行类型擦除,但这只是巧合。
As a matter of fact, once upon a time there were compilers that wouldn't accept such tricks and the boost::function
precursor had a portablesyntax by which all the parameters could be passed separately:
事实上,曾几何时有些编译器不会接受这样的技巧,而boost::function
前身有一个可移植的语法,所有参数都可以单独传递:
Preferred syntax
boost::function<void(int*, int, int&, float&)> sum_avg;
Portable syntax
boost::function4<void, int*, int, int&, float&> sum_avg;
首选语法
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
https://www.boost.org/doc/libs/1_68_0/doc/html/function/tutorial.html#id-1.3.16.5.4
So that's how the template parameters of std::function
work, at the end it is just a trick to make a lot of parameters look like a function call. Function pointers to that type of function are not necessarilyinvolved in the class.
所以这就是模板参数的std::function
工作方式,最后让很多参数看起来像一个函数调用只是一个技巧。指向该类型函数的函数指针不一定包含在类中。