C++11 可变参数 std::function 参数
名为 test
的函数将 std::function<>
作为其参数。
template<typename R, typename ...A>
void test(std::function<R(A...)> f)
{
// ...
}
但是,如果我执行以下操作:
void foo(int n) { /* ... */ }
// ...
test(foo);
编译器(gcc 4.6.1)说没有调用 test(void (&)(int)) 的匹配函数
。
为了使最后一行 test(foo)
编译并正常工作,如何修改 test()
函数?在 test()
函数中,我需要类型为 std::function<>
的 f
。
我的意思是,是否有任何模板技巧可以让编译器确定函数的签名(示例中的foo
),并将其转换为std::function
自动?
编辑
我想让这个也适用于 lambda(有状态和无状态)。
A function named test
takes std::function<>
as its parameter.
template<typename R, typename ...A>
void test(std::function<R(A...)> f)
{
// ...
}
But, if I do the following:
void foo(int n) { /* ... */ }
// ...
test(foo);
Compiler(gcc 4.6.1) says no matching function for call to test(void (&)(int))
.
To make the last line test(foo)
compiles and works properly, how can I modify the test()
function? In test()
function, I need f
with type of std::function<>
.
I mean, is there any template tricks to let compiler determine the signature of function(foo
in example), and convert it to std::function<void(int)>
automatically?
EDIT
I want to make this work for lambdas (both stateful and stateless) as well.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
看起来您想使用重载
这个简单的实现将接受您尝试传递的大多数(如果不是全部)函数。奇异函数将被拒绝(例如
void(int...)
)。更多的工作会给你更多的通用性。It looks like you want to use overloading
This simple implementation will accept most if not all the functions you will try to pass. Exotic functions will be rejected (like
void(int...)
). More work will give you more genericity.std::function
实现了 Callable 接口,即它看起来像一个函数,但这并不意味着您应该要求可调用对象是std::function
。鸭子类型是模板元编程中的最佳策略。接受模板参数时,不要具体,只让客户端实现接口。
如果您确实需要一个
std::function
来重新定位变量或类似的疯狂的东西,并且您知道输入是原始函数指针,那么您可以分解原始函数指针类型并将其重新组合为std::function
。现在用户无法传递 std::function ,因为它已封装在函数中。您可以将现有代码保留为另一个重载并仅委托给它,但要小心保持接口简单。
至于有状态的 lambda,我不知道如何处理这种情况。它们不会分解为函数指针,据我所知,不能查询或推断参数类型。无论好坏,此信息对于实例化
std::function
都是必需的。std::function
implements the Callable interface, i.e. it looks like a function, but that doesn't mean you should require callable objects to bestd::function
s.Duck typing is the best policy in template metaprogramming. When accepting a template argument, be unspecific and just let the client implement the interface.
If you really need a
std::function
for example to re-target the variable or something crazy like that, and you know the input is a raw function pointer, you can decompose a raw function pointer type and reconsitute it into astd::function
.Now the user can't pass a
std::function
because that has been encapsulated within the function. You could keep your existing code as another overload and just delegate to that, but be careful to keep interfaces simple.As for stateful lambdas, I don't know how to handle that case. They don't decompose to function pointers and as far as I know the argument types cannot be queried or deduced. This information is necessary to instantiate
std::function
, for better or worse.这是一篇旧文章,我似乎找不到太多关于同一主题的内容,所以我想我应该继续写一个注释。
在 GCC 4.8.2 上编译,可以执行以下操作:
但是,您不能仅通过传入指针、lambda 等来调用它。但是,以下 2 个示例都可以使用它:
另外:
这些的缺点应该很明显很明显:您必须为它们显式声明 std::function,这可能看起来有点难看。
尽管如此,我还是将其与一个扩展为调用传入函数的元组放在一起,并且它可以工作,只需要更多一点明确说明您正在调用测试函数做什么。
包含元组的示例代码,如果您想使用它: http://ideone.com/33mqZA
This is an old one, and I can't seem to find much on the same topic, so I thought I would go ahead and put in a note.
Compiled on GCC 4.8.2, the following works:
However, you can't just call it by passing in your pointers, lambdas, etc. However, the following 2 examples both work with it:
Also:
The downside of these should stand out pretty obviously: you have to explicitly declare the std::function for them, which might look a little bit ugly.
That said, though, I threw that together with a tuple that gets expanded to call the incoming function, and it works, just requiring a little bit more of an explicitly saying what you're doing calling the test function.
Example code including the tuple thing, if you want to play with it: http://ideone.com/33mqZA
通常不建议按值接受
std::function
,除非您处于“二进制定界”(例如动态库、“不透明”API),因为正如您刚刚目睹的那样,它们对重载造成了严重破坏。当函数实际上按值获取 std::function 时,调用者通常有责任构造对象以避免重载问题(如果函数完全重载)。由于您编写了模板,因此很可能您没有使用 std::function(作为参数类型)来获得类型擦除的好处。如果您想要做的是检查任意函子,那么您需要一些特征。例如,Boost.FunctionTypes 具有
result_type
和parameter_types
等特征。一个最小的函数示例:最后一点,我不建议在一般情况下内省函子(即刺激其结果类型和参数类型),因为这对于多态函子根本不起作用。考虑几个重载的的容器中时。
operator()
:那么就没有“规范的”结果类型或参数类型。对于 C++11,最好“热切”接受任何类型的函子,或者根据需要使用 SFINAE 或static_assert
等技术来约束它们,然后(当参数可用时)使用 < code>std::result_of 检查给定参数集的结果类型。需要预先约束的情况是当目标是将函子存储到例如 std::function为了了解我上一段的意思,用多态函子测试上面的代码片段就足够了。
It's usually ill-advised to accept
std::function
by value unless you are at 'binary delimitation' (e.g. dynamic library, 'opaque' API) since as you've just witnessed they play havoc with overloading. When a function does in fact take anstd::function
by value then it's often the burden of the caller to construct the object to avoid the overloading problems (if the function is overloaded at all).Since however you've written a template, it's likely the case that you're not using
std::function
(as a parameter type) for the benefits of type-erasure. If what you want to do is inspecting arbitrary functors then you need some traits for that. E.g. Boost.FunctionTypes has traits such asresult_type
andparameter_types
. A minimal, functional example:As a final note, I do not recommend introspecting functors (i.e. prodding for their result type and argument types) in the general case as that simply don't work for polymorphic functors. Consider several overloaded
operator()
: then there is no 'canonical' result type or argument types. With C++11 it's better to 'eagerly' accept any kind of functor, or constrain them using techniques like SFINAE orstatic_assert
depending on the needs, and later on (when parameters are available) to usestd::result_of
to inspect the result type for a given set of arguments. A case where constraining up front is desirable is when the aim is to store functors into e.g. a container ofstd::function<Sig>
.To get a taste of what I mean by the previous paragraph it's enough to test the above snippet with polymorphic functors.