首页 > STL编程 > no matching function for call to transform

no matching function for call to transform

文章得从《C++标准程序库》中的一个源代码说起。今天看到了第11章String,于是敲了书上的源代码,在Ubuntu下一编译,靠,竟然报错了。

STL报错那是什么概念……信息异常混乱啊!于是就直接去Google搜索错误提示关键字了。恩,找到了相关问题,同样也是《C++标准程序库》上的这份代码造成的。

现来看一下代码吧:

#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
using namespace std;

int main()
{
	string s("The zip code of Hondelage in Germany is 38108");
	cout << "original: " << s << endl;
	
	transform(s.begin(), s.end(),
			 s.begin(), tolower);
	cout << "lowered: " << s << endl;
	
	transform(s.begin(), s.end(),
			 s.begin(), toupper);
	cout << "uppered: " << s << endl;
	
	return 0;
}

错误提示如下:

striter1.cpp: In function ‘int main()’:
striter1.cpp:13: error: no matching function for call to ‘transform(__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, <unresolved overloaded function type>)’
striter1.cpp:17: error: no matching function for call to ‘transform(__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, <unresolved overloaded function type>)’
lk@ubuntu:~/STL/Ch11$
确实很“复杂”,看起来头晕。看看达人的解释:

在<cctype>里面声明了一个C版本的函数tolower,int tolower(int); 而在<local>中间也声明了一个函数模板:

template <class charT>
charT tolower( charT c , const locale& loc );

如果这两个头文件都同时包含到程序中来的话(C++标准头文件可能会包含另外的标准头文件。例如有的编译器在一些标准头文件中,如<iostream>,会包含<locale>或<cctype>头文件。这样,包含<iostream>可能会引入<locale>或<cctype>),由于这些 tolower 函数都位于同一 std 名字空间,于是形成了函数重载。这样的话,transform 函数(也是一个模板函数)的第四个参数是tolower 的时候,此时给定的 tolower 只是作为一个函数指针使用,缺乏类型推导所需要的函数参数信息,所以无法推导出函数的类型,也就无法决定使用哪一个重载函数。

如果想使用非模版的 tolower 函数,有多种方法可以解决:

transform( s.begin(), s.end(), s.begin(), (int(*)(int))tolower);

或者

int (*pf)( int ) = tolower; // pf 是一个函数指针,其类型已经明确。
transform( s.begin(), s.end(), s.begin(), pf );

或者

// 使用一个包装函数,避免直接使用 tolower 函数由于重载带来的问题。
int my_tolower( int c )
{
return tolower( c ); // 根据 c 的类型可以确定使用 tolower 的哪个重载函数。
}

// …
// my_tolower 是非模版非重载函数,避免了函数重载带来的类型解析问题。
transform( s.begin(), s.end(), s.begin(), my_tolower );

另外,非模板函数的 tolower 其实是来自于标准 C 库函数,因此在 C++ 标准库中它同时位于全局和 std 名字空间。既然 std 名字空间内 tolower 函数有可能形成函数重载,但是在全局名字空间中的 tolower 函数却只有一个,所以也可以直接使用全局名字空间中的 tolower:

transform( s.begin(), s.end(), s.begin(), ::tolower);

当然,模板函数和非模板函数 tolower 的区别还是很明显的:前者有两个参数,后者只有一个参数。而程序中使用的 transform 函数的第四个参数要求,如果是函数的话只能是有一个参数的函数,所以从这方面来说重载函数的选择问题是可以得到解决的。有的编译器可能就是根据这一点做了进一步的判别处理,或者直接选择了非模版函数,从而解决了这一问题。但是 C++ 标准并没有要求一定要解决类似的不确定问题,所以无论编译器是怎样处理的,解决或者没有解决,应该都是符合标准的。

至此,问题成功解决。下面再帖一下成功编译的函数代码:

#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
using namespace std;

int main()
{
	string s("The zip code of Hondelage in Germany is 38108");
	cout << "original: " << s << endl;
	
	transform(s.begin(), s.end(),
			 s.begin(), ::tolower);
	cout << "lowered: " << s << endl;
	
	transform(s.begin(), s.end(),
			 s.begin(), ::toupper);
	cout << "uppered: " << s << endl;
	
	return 0;
}

程序的运行结果截图如下:

程序运行结果

总结:

不要小看这一段代码很简单,没有必要敲,结果了,学习到了不少知识。呵呵


觉得文章还不错?点击此处对作者进行打赏!


本文地址: 程序人生 >> no matching function for call to transform
作者:代码疯子(Wins0n) 本站内容如无声明均属原创,转载请保留作者信息与原文链接,谢谢!


更多



分类: STL编程 标签: , , ,
  1. 2010年10月12日04:41 | #1

    贵站链接已加。。。可否与小站链接一下!
    呵呵。。。
    龙之谷

    [回复]

    代码疯子 回复:

    不好意思,不能与贵站做友链,只和“电脑技术相关博客”做链接。

    [回复]

  2. 2010年10月12日08:04 | #2

    呵呵一说到代码就犯困因为我都不会啊

    [回复]

    代码疯子 回复:

    恩 不搞这方面的看起来是很头晕

    [回复]

  3. 2010年10月12日11:32 | #3

    温习下,以前在学校时,我们C++老师天天讲,那时不是很用心的学,呵呵~

    [回复]

    代码疯子 回复:

    呵呵 现在已经工作了吗?

    [回复]

  4. 2010年10月12日13:14 | #4

    有点高深啊,有时间我也得研究下曾经学的Java了。

    [回复]

    代码疯子 回复:

    呵呵 我本来搞这方面的,不研究点 怕出去没饭吃

    [回复]

  1. 本文目前尚无任何 trackbacks 和 pingbacks.