C++ 如何指定指向重载函数的指针?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2942426/
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 do I specify a pointer to an overloaded function?
提问by davka
I want to pass an overloaded function to the std::for_each()
algorithm. For example,
我想将重载的函数传递给std::for_each()
算法。例如,
class A {
void f(char c);
void f(int i);
void scan(const std::string& s) {
std::for_each(s.begin(), s.end(), f);
}
};
I'd expect the compiler to resolve f()
by the iterator type. Apparently, it (GCC 4.1.2) doesn't do it. So, how can I specify which f()
I want?
我希望编译器能够f()
通过迭代器类型进行解析。显然,它(GCC 4.1.2)没有这样做。那么,我该如何指定f()
我想要的呢?
采纳答案by In silico
You can use static_cast<>()
to specify which f
to use according to the function signature implied by the function pointer type:
您可以根据函数指针类型所隐含的函数签名static_cast<>()
来指定使用哪个f
:
// Uses the void f(char c); overload
std::for_each(s.begin(), s.end(), static_cast<void (*)(char)>(&f));
// Uses the void f(int i); overload
std::for_each(s.begin(), s.end(), static_cast<void (*)(int)>(&f));
Or, you can also do this:
或者,您也可以这样做:
// The compiler will figure out which f to use according to
// the function pointer declaration.
void (*fpc)(char) = &f;
std::for_each(s.begin(), s.end(), fpc); // Uses the void f(char c); overload
void (*fpi)(int) = &f;
std::for_each(s.begin(), s.end(), fpi); // Uses the void f(int i); overload
If f
is a member function, then you need to use mem_fun
, or for your case, use the solution presented in this Dr. Dobb's article.
如果f
是成员函数,则您需要使用mem_fun
,或者对于您的情况,请使用Dobb 博士的文章中提供的解决方案。
回答by milleniumbug
Lambdas to the rescue! (note: C++11 required)
Lambda 来救援!(注意:需要 C++11)
std::for_each(s.begin(), s.end(), [&](char a){ return f(a); });
Or using decltype for the lambda parameter:
或者对 lambda 参数使用 decltype:
std::for_each(s.begin(), s.end(), [&](decltype(*s.begin()) a){ return f(a); });
With polymorphic lambdas (C++14):
使用多态 lambdas (C++14):
std::for_each(s.begin(), s.end(), [&](auto a){ return f(a); });
Or disambiguate by removing overloading (only works for free functions):
或者通过删除重载来消除歧义(仅适用于自由函数):
void f_c(char i)
{
return f(i);
}
void scan(const std::string& s)
{
std::for_each(s.begin(), s.end(), f_c);
}
回答by Barry
Why doesn't it work
为什么它不起作用
I'd expect the compiler to resolve
f()
by the iterator type. Apparently, it (gcc 4.1.2) doesn't do it.
我希望编译器能够
f()
通过迭代器类型进行解析。显然,它(gcc 4.1.2)没有这样做。
It'd be great if that were the case! However, for_each
is a function template, declared as:
如果真是这样就好了!然而,for_each
是一个函数模板,声明为:
template <class InputIterator, class UnaryFunction>
UnaryFunction for_each(InputIterator, InputIterator, UnaryFunction );
Template deduction needs to select a type for UnaryFunction
at the point of the call. But f
doesn't have a specific type - it's an overloaded function, there are many f
s each with different types. There is no current way for for_each
to aid the template deduction process by stating which f
it wants, so template deduction simply fails. In order to have the template deduction succeed, you need to do more work on the call site.
模板推导需要UnaryFunction
在调用时选择一种类型。但是f
没有特定的类型——它是一个重载的函数,有很多f
s,每个都有不同的类型。当前没有for_each
方法通过说明f
它想要的方式来帮助模板推导过程,因此模板推导完全失败。为了使模板推演成功,您需要在调用站点上做更多的工作。
Generic solution to fixing it
修复它的通用解决方案
Hopping in here a few years and C++14 later. Rather than use a static_cast
(which would allow template deduction to succeed by "fixing" which f
we want to use, but requires you to manually do overload resolution to "fix" the correct one), we want to make the compiler work for us. We want to call f
on some args. In the most generic way possible, that's:
几年后跳到这里,然后在 C++14 中跳来跳去。而不是使用 a static_cast
(这将允许通过“修复”f
我们想要使用的模板推导成功,但需要您手动进行重载解析以“修复”正确的),我们想让编译器为我们工作。我们想调用f
一些参数。以最通用的方式,那就是:
[&](auto&&... args) -> decltype(auto) { return f(std::forward<decltype(args)>(args)...); }
That's a lot to type, but this sort of problem comes up annoyingly frequently, so we can just wrap that in a macro (sigh):
需要输入的内容很多,但这类问题经常出现令人讨厌,因此我们可以将其包装在一个宏中(叹气):
#define AS_LAMBDA(func) [&](auto&&... args) -> decltype(func(std::forward<decltype(args)>(args)...)) { return func(std::forward<decltype(args)>(args)...); }
and then just use it:
然后就用它:
void scan(const std::string& s) {
std::for_each(s.begin(), s.end(), AS_LAMBDA(f));
}
This will do exactly what you wish the compiler did - perform overload resolution on the name f
itself and just do the right thing. This will work regardless of whether f
is a free function or a member function.
这将完全符合您希望编译器所做的事情 - 对名称f
本身执行重载解析,然后做正确的事情。无论f
是自由函数还是成员函数,这都将起作用。
回答by Barry
Not to answer your question, but am I the only one that finds
不是要回答你的问题,但我是唯一一个找到的人吗
for ( int i = 0; i < s.size(); i++ ) {
f( s[i] );
}
both simpler and shorter than the for_each
alternative suggested by in silico in this case?
for_each
在这种情况下,比in silico 建议的替代方案更简单和更短?
回答by aldo
The problem here seems to be not overload resolutionbut in fact template parameter deduction. While the excellent answerfrom @In silico will solve an ambiguous overloading problem in general, it seems the best fix when dealing with std::for_each
(or similar) is to explicitly specify its template parameters:
这里的问题似乎不是重载解析,而是模板参数推导。虽然来自@In silico的优秀答案通常会解决一个模棱两可的重载问题,但处理std::for_each
(或类似)时的最佳解决方案似乎是明确指定其模板参数:
// Simplified to use free functions instead of class members.
#include <algorithm>
#include <iostream>
#include <string>
void f( char c )
{
std::cout << c << std::endl;
}
void f( int i )
{
std::cout << i << std::endl;
}
void scan( std::string const& s )
{
// The problem:
// error C2914: 'std::for_each' : cannot deduce template argument as function argument is ambiguous
// std::for_each( s.begin(), s.end(), f );
// Excellent solution from @In silico (see other answer):
// Declare a pointer of the desired type; overload resolution occurs at time of assignment
void (*fpc)(char) = f;
std::for_each( s.begin(), s.end(), fpc );
void (*fpi)(int) = f;
std::for_each( s.begin(), s.end(), fpi );
// Explicit specification (first attempt):
// Specify template parameters to std::for_each
std::for_each< std::string::const_iterator, void(*)(char) >( s.begin(), s.end(), f );
std::for_each< std::string::const_iterator, void(*)(int) >( s.begin(), s.end(), f );
// Explicit specification (improved):
// Let the first template parameter be derived; specify only the function type
std::for_each< decltype( s.begin() ), void(*)(char) >( s.begin(), s.end(), f );
std::for_each< decltype( s.begin() ), void(*)(int) >( s.begin(), s.end(), f );
}
void main()
{
scan( "Test" );
}
回答by Matthew
If you don't mind using C++11, here's a clever helper that is similar to (but less ugly than) the static cast:
如果您不介意使用 C++11,这里有一个聪明的助手,它类似于(但没有那么难看)静态类型转换:
template<class... Args, class T, class R>
auto resolve(R (T::*m)(Args...)) -> decltype(m)
{ return m; }
template<class T, class R>
auto resolve(R (T::*m)(void)) -> decltype(m)
{ return m; }
(Works for member functions; should be obvious how to modify it to work for freestanding functions, and you shouldbe able to provide both versions and the compiler will select the right one for you.)
(适用于成员函数;应该很明显如何修改它以适用于独立函数,并且您应该能够提供两个版本,编译器将为您选择正确的一个。)
With thanks to Miro Knejp for suggesting: see also https://groups.google.com/a/isocpp.org/d/msg/std-discussion/rLVGeGUXsK0/IGj9dKmSyx4J.
感谢 Miro Knejp 的建议:另见https://groups.google.com/a/isocpp.org/d/msg/std-discussion/rLVGeGUXsK0/IGj9dKmSyx4J。