我如何指定一个重载函数的指针?

我想传递一个重载的函数到std::for_each()algorithm。 例如,

 class A { void f(char c); void f(int i); void scan(const std::string& s) { std::for_each(s.begin(), s.end(), f); } }; 

我希望编译器通过迭代器types来parsingf() 。 显然,它(GCC 4.1.2)不这样做。 那么,我怎样才能指定我想要哪个f()

您可以使用static_cast<>()根据函数指针types所隐含的函数签名指定要使用的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)); 

或者,你也可以这样做:

 // 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 

如果f是一个成员函数,那么你需要使用mem_fun ,或者根据你的情况,使用Dobb博士的文章中提出的解决scheme 。

兰巴达去救援! (注意:需要C ++ 11)

 std::for_each(s.begin(), s.end(), [&](char a){ return f(a); }); 

或者使用decltype作为lambda参数:

 std::for_each(s.begin(), s.end(), [&](decltype(*s.begin()) a){ return f(a); }); 

使用多态lambdaexpression式(C ++ 14):

 std::for_each(s.begin(), s.end(), [&](auto a){ return f(a); }); 

或消除重载消除(只适用于免费function):

 void f_c(char i) { return f(i); } void scan(const std::string& s) { std::for_each(s.begin(), s.end(), f_c); } 

为什么它不工作

我希望编译器通过迭代器types来parsingf() 。 显然,它(海湾合作委员会4.1.2)不这样做。

如果是这样的话,那真是太好了! 但是, for_each是一个函数模板,声明如下:

 template <class InputIterator, class UnaryFunction> UnaryFunction for_each(InputIterator, InputIterator, UnaryFunction ); 

模板扣除需要在呼叫时为UnaryFunctionselect一个types。 但是f没有特定的types – 它是一个重载函数,每个types都有很多f 。 对于for_each ,目前还没有任何方法可以帮助模板扣除过程,因为它说明了它需要哪个f ,所以模板扣除就会失败。 为了使模板扣除成功,您需要在呼叫站点上做更多的工作。

通用的解决scheme来解决它

在这里跳了几年,C ++ 14以后。 我们不是使用static_cast (这将允许通过“修复”我们想使用的模板来获得成功,但需要手动进行重载parsing来“修复”正确的),我们希望使编译器为我们工作。 我们想在一些参数上调用f 。 以最通用的方式,即:

 [&](auto&&... args) -> decltype(auto) { return f(std::forward<decltype(args)>(args)...); } 

键入的内容很多,但是这样的问题出现频繁,所以我们可以用macros(叹气)来包装它:

 #define AS_LAMBDA(func) [&](auto&&... args) -> decltype(auto) { return func(std::forward<decltype(args)>(args)...); } 

然后使用它:

 void scan(const std::string& s) { std::for_each(s.begin(), s.end(), AS_LAMBDA(f)); } 

这将完全符合你希望编译器所做的 – 对名称f本身执行重载parsing,并做正确的事情。 无论f是一个自由函数还是一个成员函数,这都可以工作。


P0119R1会允许你刚刚通过f并且刚刚工作,但这在Oulu被拒绝了。 它可能在Issaquah以不同的forms回来,但它不会在C ++ 17中。

不回答你的问题,但我是唯一的发现

 for ( int i = 0; i < s.size(); i++ ) { f( s[i] ); } 

在这种情况下,它们是否比在这个计算机上提供的for_eachselect更简单和更短?

这里的问题似乎不是重载决议,而是实际上模板参数的扣除 。 虽然@In silico的优秀答案通常会解决一个模糊的重载问题,但在处理std::for_each (或类似的)时,似乎是明确指定其模板参数的最佳解决scheme:

 // 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" ); } 

如果你不介意使用C ++ 11,下面是一个聪明的帮手,它和静态types相似(但不是那么丑陋):

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

(适用于成员函数;应该很明显如何修改它以适用于独立函数,而且您应该能够提供这两个版本,编译器将为您select合适的版本。)

感谢Miro Knejpbuild议:另请参阅https://groups.google.com/a/isocpp.org/d/msg/std-discussion/rLVGeGUXsK0/IGj9dKmSyx4J