布尔型和字符串类型的赋值运算符重载(C++)

6
我将定义多个重载的赋值运算符,如下所示:
Foo.h
class Foo
{
private:
    bool my_bool;
    int my_int;
    std::string my_string;
public:
    Foo& operator= (bool value);
    Foo& operator= (int value);
    Foo& operator= (const std::string& value);
};

Foo.cpp

// Assignment Operators.
Foo& Foo::operator= (bool value) {my_bool = value; return *this;}
Foo& Foo::operator= (int value) {my_int = value; return *this;}
Foo& Foo::operator= (const std::string& value) {my_string = value; return *this;}

以下是我的main.cpp(请查看标有SURPRISE的注释):

Foo boolFoo;
Foo intFoo;
Foo stringFoo;

// Reassign values via appropriate assignment operator.
boolFoo = true;                // works...assigned as bool
intFoo = 42;                   // works...assigned as int
stringFoo = "i_am_a_string";   // SURPRISE...assigned as bool, not string

std::string s = "i_am_a_string";
stringFoo = s;                 // works...assigned as string

// works...but awkward
stringFoo = static_cast<std::string>("i_am_a_string");

问题:有人能告诉我为什么未转换的字符串文字在布尔上下文中被评估吗?


@Mooing Duck:为什么要删除构造函数?我添加它们是有意为之的,以表明变量可以通过构造函数进行初始化,然后通过赋值运算符进行重新分配。(正如我在其他SO帖子中看到的那样,有时您需要两者兼备。) - DavidRR
2
我缩减了代码,因为好问题应该有一个简短的自包含可编译示例你的代码可以更短更简单,仍然能够重现问题。第一次我没有读完你的大部分问题,因为里面的代码太多了,而且我猜测(正确地)其中大部分与你的问题无关。 - Mooing Duck
@Mooing Duck:是的,我非常赞同这个原则,并在添加构造函数到我的示例时考虑过这一点。但是我会听从你的判断。然而,我的希望是任何看到我的评论的人都能考虑相关的构造函数。 - DavidRR
我不明白,为什么你希望他们考虑相关的构造函数?构造函数可能与类似的问题有关,但在这个问题中完全无关。如果他们看到构造函数,那可能会让人们认为这与他们的构造函数有关。 - Mooing Duck
@Mooing Duck: 感谢您的持续推动。现在我真正领悟到的是,无论Foo是构造函数还是其他任何方法,方法签名Foo(std::string&)Foo(char*)是非常不同的。所以,我现在意识到我理解上的差距实际上已经超越了我在发布问题时看到的赋值运算符的情况。 - DavidRR
2个回答

12
C++标准在第13.3章中定义了重载解析规则,其中包括以下内容:
13.3.3.2 隐式转换序列排名 [over.ics.rank]
2. 当比较隐式转换序列的基本形式(如13.3.3.1中所定义)时: - 标准转换序列(13.3.3.1.1)优于用户自定义转换序列或省略号转换序列。 - 用户自定义转换序列(13.3.3.1.2)优于省略号转换序列(13.3.3.1.3)。
这意味着如果存在从字符串字面值到布尔型或整型的标准转换序列,则编译器会更倾向于使用它们。那么,哪些标准转换是相关的呢?在您的情况下,以下两种是相关的:

4.2 数组到指针的转换 [conv.array]

1 类型为“数组类型N T”或“未知边界数组类型T”的左值或右值可以转换为类型为“指向T的指针”的纯右值。结果是数组的第一个元素的指针。

这个转换将字符串字面值,它的类型是const char[N],转换为const char*。第二个是:

4.12 布尔类型转换 [conv.bool]

1 算术类型、无作用域枚举类型、指针类型或成员指针类型的纯右值可以转换为类型为bool的纯右值。零值、空指针值或空成员指针值被转换为false;任何其他值都被转换为true。类型为std::nullptr_t的纯右值可以转换为类型为bool的纯右值;结果值为false

这就是指针转换为 bool 的原因。由于存在标准转换序列,因此不会使用用户定义的转换到 std::string
为解决你的问题,我建议你添加另一个重载版本,接受 const char* 并将其转发到 const std::string& 重载。

谢谢,丹尼尔!我从这里学到的另一个教训是,字符串字面值映射到 char *(通过 char[N]),而不是 std::string - DavidRR
2
@DavidRR:应该是const char*const char[N],但是没错。 - Mooing Duck

4

Daniel是正确的。

简短的回答是,std::string不是内置类型,因此不会得到任何神奇的优先处理。很不幸,像"hi world"这样的字符串文字的类型不是std::string,而是指针类型,它比“用户定义”的类型std::string更容易转换为内置类型bool

基本上,答案是:欢迎来到C++。

是的,我知道,它来自于标准库,但无论如何都没有关系。


我认为有人给你的帖子点了踩,因为最后一句话听起来有点讽刺。 - Mooing Duck
2
@Mooing:如果它是讽刺的,那么它是针对C++的。如果有人把那个当成个人攻击,那么,他们已经超出了我的帮助范围。 - Lightness Races in Orbit
作为提问者,我并不对“欢迎来到C++”感到冒犯。我发现C++与Java和C#非常不同。在C++中,似乎有更多的机会惹麻烦... - DavidRR
换句话说,额外的灵活性伴随着额外的责任。 - DavidRR
换句话说,就是“跑路躲起来” :) - Lightness Races in Orbit
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接