繁体   English   中英

自动类型转换为std :: string和char *之间的C ++差异

[英]C++ difference between automatic type conversion to std::string and char*

作为一个学习练习,我一直在研究自动类型转换在C ++中的工作原理。 知道通常应该避免自动类型转换,但我想通过了解它的工作原理来增加我对C ++的了解。

我创建了一个可以自动转换为std::stringStdStringConverter类,但是当对象与真正的std::string进行比较时,编译器(Debian上的g ++ 4.3.4)似乎没有进行转换(请忽略没有传递引用和不必要的临时对象创建):

#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::stringchar*之间的区别有什么特别之处,这使得编译器不会对它们进行相同的处理吗?

问题是由于std :: string实际上是类模板std :: basic_string的一个实例。 在命名空间std中可用的operator ==需要两个std :: basic_string模板:


template<class charT, class traits, class Allocator>
bool operator==(const basic_string& lhs,
                const basic_string& rhs);

如果这个版本的operator ==专门在std :: string上重载,那么你的代码就可以了。 但事实并非如此,这需要编译器对std :: basic_string的模板参数执行模板参数推断,这样才能理解转换运算符的返回是可能的匹配。

但是,编译器不会这样做。 我不知道标准的哪一部分准确说明了这一点。 但一般的想法是,此类转换仅适用于非模板类型。

我可以建议的一件事是将StdStringConverter放在命名空间中,并在该命名空间中为std :: string提供operator ==的版本。 这样,当您的编译器找到类似ADL(Argument Dependent Lookup)的表达式时,一切正常。


#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)没有从编译器获得任何特殊处理以进行类型转换。 这意味着您所做的操作员超载甚至不会被触发。 编译器查看operator ==重载的列表,而不是它们接收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;
}

现在程序返回0.由于构造函数现在不是显式的,编译器将尝试使用它将字符串转换为StdStringConverter。 由于现在StdStringConverter中有一个operator ==,一切正常。

有多种因素。 如果你这样改变了return语句

return(std :: operator ==(name,name))? 0:1;

它编译,虽然它显然不会做同样的事情。 另一方面

return(std :: operator ==(转换器,名称))? 0:1;

不会提供更有趣的错误消息

调用'operator ==(StdStringConverter&,const std :: string&)没有匹配函数

这提醒我,operator ==是在basic_string <>上模板化的,它有三个模板参数可以启动。 如果在示例中使用int而不是std :: string,则编译器不会抱怨。

如何用std :: string获得所需的效果更有趣......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM