我想将重载函数传递给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);
}
};
Run Code Online (Sandbox Code Playgroud)
我期望编译器f()通过迭代器类型来解析.显然,它(GCC 4.1.2)没有这样做.那么,我该如何指定f()我想要的?
In *_*ico 129
您可以根据函数指针类型隐含的函数签名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));
Run Code Online (Sandbox Code Playgroud)
或者,您也可以这样做:
// 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
Run Code Online (Sandbox Code Playgroud)
如果f是成员函数,那么您需要使用mem_fun或者根据您的情况使用Dr. Dobb的文章中提供的解决方案.
mil*_*bug 25
Lambdas救援!(注意:需要C++ 11)
std::for_each(s.begin(), s.end(), [&](char a){ return f(a); });
Run Code Online (Sandbox Code Playgroud)
或者使用decltype作为lambda参数:
std::for_each(s.begin(), s.end(), [&](decltype(*s.begin()) a){ return f(a); });
Run Code Online (Sandbox Code Playgroud)
多态lambda(C++ 14):
std::for_each(s.begin(), s.end(), [&](auto a){ return f(a); });
Run Code Online (Sandbox Code Playgroud)
或者通过删除重载消除歧义(仅适用于免费功能):
void f_c(char i)
{
return f(i);
}
void scan(const std::string& s)
{
std::for_each(s.begin(), s.end(), f_c);
}
Run Code Online (Sandbox Code Playgroud)
Bar*_*rry 15
我期望编译器
f()通过迭代器类型来解析.显然,它(gcc 4.1.2)没有这样做.
如果是这样的话会很棒!但是,for_each是一个函数模板,声明为:
template <class InputIterator, class UnaryFunction>
UnaryFunction for_each(InputIterator, InputIterator, UnaryFunction );
Run Code Online (Sandbox Code Playgroud)
模板推导需要UnaryFunction在呼叫点选择类型.但是f没有特定的类型 - 它是一个重载函数,有很多fs每个都有不同的类型.目前没有办法for_each通过说明f它想要的内容来帮助模板扣除过程,因此模板扣除完全失败.为了使模板扣除成功,您需要在呼叫站点上做更多工作.
在这里跳了几年,然后是C++ 14.而不是使用static_cast(允许模板推导通过"修复" f我们想要使用的成功,但需要您手动执行重载解析以"修复"正确的),我们希望使编译器为我们工作.我们想要f一些args.以最通用的方式,这是:
[&](auto&&... args) -> decltype(auto) { return f(std::forward<decltype(args)>(args)...); }
Run Code Online (Sandbox Code Playgroud)
键入的内容很多,但是这种问题经常出现,所以我们可以将它包装在宏(叹息)中:
#define AS_LAMBDA(func) [&](auto&&... args) -> decltype(func(std::forward<decltype(args)>(args)...)) { return func(std::forward<decltype(args)>(args)...); }
Run Code Online (Sandbox Code Playgroud)
然后使用它:
void scan(const std::string& s) {
std::for_each(s.begin(), s.end(), AS_LAMBDA(f));
}
Run Code Online (Sandbox Code Playgroud)
这将完全按照您希望的编译器执行 - 对名称f本身执行重载解析并执行正确的操作.无论f是自由函数还是成员函数,这都可以工作.
小智 6
不是回答您的问题,而是我是唯一找到的人
for ( int i = 0; i < s.size(); i++ ) {
f( s[i] );
}
Run Code Online (Sandbox Code Playgroud)
for_each在这种情况下,比in silico建议的替代方案更简单,更短?
如果您不介意使用 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; }
Run Code Online (Sandbox Code Playgroud)
(适用于成员函数;如何修改它以适用于独立函数应该是显而易见的,并且您应该能够提供两个版本,编译器将为您选择正确的版本。)
感谢 Miro Knejp 的建议:另请参阅https://groups.google.com/a/isocpp.org/d/msg/std-discussion/rLVGeGUXsK0/IGj9dKmSyx4J。
这里的问题似乎不是过载解析,而是实际上模板参数的推导。虽然@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" );
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
32800 次 |
| 最近记录: |