C ++自动类型转换之间差的std :: string与char *
-
22-07-2019 - |
题
作为一个学习练习,我一直在寻找自动类型转换用C如何工作++。我的知道的那个类型的自动转换一般应避免,但我想通过了解它是如何工作无论如何增加我的C ++知识。
我已经创建了可以被自动转换为一个StdStringConverter
类std::string
,但是编译器(克++ 4.3.4在Debian)似乎当对象被针对真实std::string
相比不进行转换(请忽略缺乏通过按引用和临时对象的不必要创建):
#include <string>
class StdStringConverter
{
public:
explicit StdStringConverter(std::string name) : m_name(name) {}
operator const std::string () const { return m_name; }
private:
std::string m_name;
};
int main()
{
StdStringConverter converter(std::string("Me"));
const std::string name = "Me";
// Next line causes compiler error:
// no match for 'operator==' in 'converter == name'
return (converter == name) ? 0 : 1;
}
在另一方面,如果我稍微改变它的CStringConverter
类,自动转换的不的发生,虽然可能比较char
指针是不是我想要的结果:
#include <string>
class CStringConverter
{
public:
explicit CStringConverter(std::string name) : m_name(name) {}
operator const char* () const { return m_name.c_str(); }
private:
std::string m_name;
};
int main()
{
CStringConverter converter(std::string("Me"));
const char* name = "Me";
// Next line compiles fine, but they are not equal because the
// pointers don't match.
return (converter == name) ? 0 : 1;
}
有什么特殊的地方std::string
并在这方面,使编译器没有把他们同一个char*
区别?
解决方案
的问题是由于这样的事实的std :: string实际上是类模板的std :: basic_string的的一个实例。操作者==即在空间std可用采用两个标准:: basic_string的模板:
template<class charT, class traits, class Allocator>
bool operator==(const basic_string& lhs,
const basic_string& rhs);
如果这个版本的==操作符的是对的std :: string具体超载,你的代码就可以了。但是,这并非如此,这就需要编译器上性病的模板参数进行模板参数推导:: basic_string的,因此它可以了解您的转换运营商的收益是可能的搭配。
然而,编译器将不这样做。我不知道这恰恰是标准规定的哪一部分。但总的想法是,这样的转换对于非模板类型才能正常工作。
有一件事我可以建议是你把StdStringConverter在一个命名空间,并提供了性病该命名空间下一个版本的==操作符的:: string的。这样,当你的编译器发现这样的ADL(参数依赖查找)的表达式进场,一切工作正常。
#include <string>
namespace n1 {
class StdStringConverter
{
public:
explicit StdStringConverter(std::string name) : m_name(name) {}
operator std::string () { return m_name; }
private:
std::string m_name;
};
bool operator==(std::string const& a, std::string const& b)
{
return a == b; //EDIT: See Paul's comment on std::operator== here.
}
}
int main()
{
using namespace n1;
StdStringConverter converter(std::string("Me"));
std::string name = "Me";
return (converter == name) ? 0 : 1;
}
其他提示
在第一个例子中的两个被比较的类(字符串和StdStringConverter)没有得到从编译器为类型转换任何特殊处理。这意味着你所做的运算符重载甚至不被触发。该编译器会通过运营商的名单==他们的超载和非参加一个StdStringConverter所以骂你。
在第二个例子中的名称是char *。由于它是一个原始类型,则编译器试图将非原始转换到一个char *。既然你已经制定一个覆盖它的工作原理和你比较地址。
,编译器将在操作不明确的类型转换不包括原始类型。一些它需要做的是尝试使用构造函数来进行类型匹配。例如,如果你的第一个例子改成这样:
#include <string>
class StdStringConverter
{
public:
StdStringConverter(std::string name) : m_name(name) {}
bool operator==(const StdStringConverter &name) { return m_name == name.m_name; }
operator const std::string () const { return m_name; }
private:
std::string m_name;
};
int main()
{
StdStringConverter converter(std::string("Me"));
const std::string name = "Me";
// Next line causes compiler error:
// no match for 'operator==' in 'converter == name'
return (converter == name) ? 0 : 1;
}
现在由于构造目前不是明确编译器将尝试使用它的字符串转换为StdStringConverter程序返回0。由于现在有在StdStringConverter一切正常操作==。
有多种因素。如果你改变了return语句正是如此
返回(标准::运算符==(姓名,名))? 0:1;
汇编,虽然它显然不会做同样的事情。在另一方面
返回(标准::运算符==(转换器,名))? 0:1;
不但提供了一个更有趣的错误消息
有呼叫到“运算符==没有匹配的功能(StdStringConverter&,常量的std :: string&)
这让我想起那个==操作符是模板上的basic_string <>,里面有三个模板参数启动。如果你在你的例子使用int而不是的std :: string,编译器不抱怨。
如何获得具有的std :: string期望的效果是更有趣...