【发布时间】:2014-04-23 11:14:06
【问题描述】:
当调用像copy_if、transform等以一元或二元函数作为最后一个参数的C++算法时,我可以传递一个像atoi或tolower这样的C库函数吗?
例如下面的调用工作正常并给出正确的输出(在 ideone 中试过)
1) transform (foo, foo+5, bar, atoi);
2) transform (foo, foo+5, bar, ptr_fun(atoi));
3) transform(s.begin(),s.end(),s.begin(), static_cast<int (*)(int)>(tolower));
这种用法是否保证适用于所有 C++ 编译器?
《thinking in C++》一书提到“这适用于某些编译器,但不是必须的”。提到的原因是(据我了解)transform 是 C++ 函数,并期望其最后一个参数具有相同的调用约定。
该书还建议了解决此问题的方法,即在单独的 cpp 文件中创建这样的包装函数,并且不包含 iostreams 头文件。
// tolower_wrapper.cpp
string strTolower(string s) {
transform(s.begin(), s.end(), s.begin(), tolower);
return s;
}
这很好用,但我不明白这如何解决调用约定问题? transform 仍然是一个 c++ 函数,而 tolower 在 strTolower 中仍然是一个 C 函数,那么这里如何处理不同的调用约定。
【问题讨论】:
-
当由相同的编译器以相同的设置编译时,这些函数保证具有兼容的调用约定。
-
调用约定不是“C 或 C++”,而是 cdecl、stdcall 之类的东西……我看不出它应该破坏这段代码的原因。
-
这和链接有什么关系?
-
这将永远有效.. 据我所知.. 我在 Linux Mint、MacOS Leopard 和 Windows 8.1 上进行了以下尝试:适用于 Clang++、G++、MSVC2010、MSVC2012、MSVC2013 , XCode(Obj-C++)..
-
@dyp 这就是我想了解的。在 cpp book 中的思想给出的确切解释是“原因,虽然晦涩难懂,是允许库实现提供“C 链接”(意味着函数名不包含普通 C++ 函数所做的所有辅助信息)到从 C 语言继承的函数。如果是这种情况,则转换失败,因为 transform 是 C++ 函数模板,并且期望它的第四个参数具有 C++ 链接——并且不允许强制转换来更改链接。这特别适用于例如3 以上。