请考虑以下代码段:
#include <algorithm>
#include <cctype>
#include <string>
using namespace std;
void test(){
std::string str = "Hello World!";
std::transform(str.begin(), str.end(), str.begin(), tolower);
}
使用G ++编译时出现tolower
错误:未解决的重载功能。
如果删除using namespace std;
,则代码可以正常工作。
然后,我的问题是:
namespace std
与C函数之间的关系是什么?#include<ctype.h>
和#include<cctype>
之间有什么区别?虽然它们都不适用于上面的例子。std::tolower
也不起作用? std::tolower
和tolower
之间的区别是什么?答案 0 :(得分:4)
您可以使用命名空间运算符来使用tolower
的C版本,如下所示:
::tolower(); // nothing before '::' means look in the global namespaece.
这将强制编译器查找不在特定命名空间内的函数,这是所有基于C的API的情况。
至于为什么std::tolower
不起作用,我不知道。 The example of cpp reference不使用std::transform
,这可能是原因。
答案 1 :(得分:4)
namespace std
和C函数之间没有关系。但
你的代码不是C,它是C ++,所以你还必须考虑C ++函数。
与std::tolower
类似,例如<locale>
。你的问题是由于
事情的一致:
您添加的其中一个标题包含<locale>
。 C ++标题是
允许包含其他C ++标头,以及哪个标头包含哪些标头
其他标题可能因实现而异,所以
你编写的代码可以用一个编译器编译,而不是用
另一
您正在尝试将该函数作为指向函数参数的指针传递,
到函数模板,其中参数是模板类型
参数。简单地说,为了做超载分辨率
tolower
这里,编译器必须将它与类型相匹配
参数,以及为了知道参数的类型,编译器
必须根据确切的类型进行模板类型推导
函数,只有在完成重载解析后才能知道。
如果你想要<ctype.h>
中的功能(你没有,因为它会
导致未定义的行为),你可以通过包括得到它
<ctype.h>
(保证它存在于全球
命名空间)并使用::tolower
,或明确指定
你想要的超载,例如static_cast<int (*)(int)>( tolower )
(在此
特殊情况,static_cast
并不意味着类型转换,但是
显式重载解析。)
在实践中,当然,你不会做这种事情。如果你是
完成任何文本处理,你将定义所有必要的
作为功能对象类型,避免未定义的行为
将输入转换为unsigned char
:
struct ToLower
{
char operator()( char ch ) const
{
return ::tolower( static_cast<unsigned char>( ch ) );
}
};
或使用<locale>
中做与char
一起使用的功能:
class ToLower
{
std::locale myLocale; // necessary to guarantee the lifetime of the facet.
std::ctype const* myCType;
public:
ToLower( std::locale const& loc = std::locale() )
; myLocal( loc )
, myCType( &std::use_facet<std::ctype>( loc ) )
{
}
bool operator()( char ch ) const
{
return myCType->tolower( ch );
}
};
最后,WRT你的第二个问题:差异取决于版本
您正在使用的C ++和编译器。但是,在全球范围内:<ctype.h>
将函数引入全局命名空间; <cctype>
会
将它们引入命名空间std::
,并且可能(或可能不)引入
全局命名空间。 (而你的第三个问题已经存在
上面回答:std::tolower
是指一组重载函数
在<locale>
和<cctype>
中定义; ::tolower
是指单个
<ctype.h>
中定义的函数,只有tolower
相当于
::tolower
,除非您已完成using namespace std
,在这种情况下,
它将引用所提到的所有函数的重载集
上方。