重载的Bool/String歧义

13
为什么C++将我传递的字符串字面值转换为布尔值而不是字符串?
#include <iostream>

using namespace std;

class A
{
    public:
        A(string v)
        {
            cout << v;
        }

        A(bool v)
        {
            cout << v;
        }
};

int main()
{
    A("hello");
    return 0;
}

输出: 1

是因为编译器不够聪明,不能从char *自动转换到string类型,只能假定bool类型是指针的最接近类型吗?我的唯一选择是创建一个显式的char *构造函数,它基本上和string构造函数做相同的事情吗?


1
我通常更喜欢显式转换。隐式转换有一些陷阱,比如这个。请参见https://dev59.com/pXE95IYBdhLWcg3wXcnd - Fred Larson
我不确定,但是:两种转换都是可能的(将指针转换为布尔值会检查空指针)。但是将其转换为布尔值是一种内置转换,而将其转换为字符串是一种用户定义的转换(通过隐式构造函数)。现在如果我记得正确,内置的优先级高于用户定义的。 - leemes
1
可能是C++方法重载不起作用的重复问题。 - M.M
4个回答

19

如果您使用的是C++11,可以使用委托构造函数:

A(char const* s) : A(std::string(s)) { }

选择布尔类型的转换构造函数而不是std::string是因为从char const*bool的转换是标准转换,而到std::string的转换是用户定义的转换。标准转换的优先级高于用户定义的转换。


5

使用

A(string("hello"));

它将会给出期望的结果。
为什么呢?这是由于标准转换:
- "hello" 被理解为一个 `const char*` 指针。 - 这个指针可以被转换成一个 `bool`(参见标准的第 4.12 节:“一个 prvalue(即纯右值)的指向对象的指针类型,可以被转换为 prvalue 的 bool 类型”)。 - `"hello"` 到 `string` 的转换没有被考虑,因为标准的第 12.3 节解释了“类对象的类型转换可以通过构造函数和转换函数来指定。这些转换称为用户自定义转换”,并且“用户自定义转换只会在它们不会引起歧义的情况下应用”。如果你有 `bool` 构造函数,`std::string` 转换将隐含进行。
如何得到你期望的结果?
只需添加缺失的字符串字面量构造函数即可:
A(const char* v)
{
    cout << v;  // or convert v to string if you want to store it in a string member
}

当然,您可以选择使用委托,而不是从头开始重写构造函数,正如0x499602D2在另一个答案中建议的那样。

是的,但我不想每次都打出 string(...)。我的另一个选择是创建一个以 char const * 为参数的构造函数吗? - Gillespie
是的!我已经完成了,附加了一些解释。 - Christophe

4

最近我也遇到这个问题,让我分享另一种解决方法。

你可以将 bool 构造函数更改为 unsigned char。这样可以避免字符串字面量的衰减和隐式转换,从而触发 std::string 构造函数。

class A
{
public:
    A(string v)
    {
        cout << v;
    }

    A(unsigned char v)
    {
        cout << static_cast<bool>(v);
    }
};

int main()
{
     A("Hello"); // <- Call A(string)
     A(false);   // <- Call A(unsigned char)
}

这样一来,您就不必总是提供std :: stringconst char * 的重载,也不必在客户端调用站点构造std::string, 从而避免了代码膨胀问题。
我并不认为这种方法更好,但它更简单。

我曾经遇到过同样的问题,但我想知道为什么 A("Hello"); 不会产生警告,而 const char *b = "Hello"; A(b); 却会产生警告 4800:强制将值转换为布尔值“true”或“false”? - shadow_map
这对我也起作用,并且在使用新的 string_view 时也非常有用。请参见此处的示例。 - Claudius
这是一个非常有用和实用的答案。这个答案对我帮助很大。 - undefined

2
当选择一个重载方法时,编译器的尝试顺序如下:
  1. 精确匹配
  2. 提升
  3. 标准数字转换
  4. 用户定义的运算符
指针不能提升为 bool,但可以转换为 boolchar* 使用 std 运算符转换为 std::string。请注意,如果 char* 在此列表中使用相同的数字来将值转换为 同时boolstd::string,编译器无法确定应该选择哪个方法,因此会抛出“重载模糊”错误。
我支持 0x499602D2 的解决方案。如果您使用的是 C++11,则最好调用:A(char* s) : A(std::string(s)){} 如果您不使用 C++11,则可以创建一个 A(char* s) 构造函数,并将 A(std::string) 构造函数的逻辑抽象成一个方法,并从这两个构造函数中调用该方法。 http://www.learncpp.com/cpp-tutorial/76-function-overloading/

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