字符串文字与布尔重载匹配,而不是std::string

54

我正在尝试编写一个C++类,其中包含一些重载的方法:

class Output
{
public:
    static void Print(bool value)
    {
        std::cout << value ? "True" : "False";
    }

    static void Print(std::string value)
    {
        std::cout << value;
    }
};

现在假设我按以下方式调用该方法:
Output::Print("Hello World");

这是结果

那么,既然我定义了该方法可以接受布尔值和字符串,为什么在我传递非布尔类型的值时会使用布尔重载呢?

编辑:我来自C#/Java环境,对C ++相当陌生!


1
因为它们不是实例函数,所以@meh。 - Matthew Layton
2
你的 const char* 是本地类型提升为布尔值,以及构造值类型提升为 std::string。你会选择哪一个?现在猜猜编译器选择了哪一个... - WhozCraig
你正在传递一个常量字符指针,而不是一个字符串,请尝试使用Output::Print(std::string("Hello World"))。 - jmetcalfe
3
关于 "static":在 C++ 中,函数可以摆脱类系统的束缚,因此你不需要像在 Java 中必须做的准类一样。 - molbdnilo
@molbdnilo,是的,我知道你可以有无类函数,有点像JavaScript,其中函数不需要绑定到原型...再次说明,由于我对C++还很陌生,所以我不确定这里的最佳实践是什么。 - Matthew Layton
4个回答

64

"Hello World"是一个类型为"12个const char的数组"的字符串字面量,它可以转换为一个"指向const char的指针",这个指针又可以转换为一个bool类型。这正是正在发生的事情。编译器更喜欢这种方式,而不是使用std::string的转换构造函数。

涉及到转换构造函数的转换序列称为用户定义的转换序列。从"Hello World"bool的转换是一个标准转换序列。标准规定,标准转换序列总是优于用户定义的转换序列(§13.3.3.2/2):

  

标准转换序列(13.3.3.1.1)优于用户定义的转换序列或省略号转换序列

对于每个可行函数的每个参数(你只有一个参数),都会进行这种"更好的转换序列"分析,并通过重载决议选择更好的函数。

如果您想确保调用std::string版本,则需要给它提供一个std::string

Output::Print(std::string("Hello World"));

1
@LuchianGrigore 我同意这是一个更深层次的问题。我只是不确定原帖作者是否了解他提出了这个问题 =P - WhozCraig
1
是的,我尝试过那个,它可以工作...只是看起来有点凌乱!我已经将方法声明更改为Print(const char* value),这似乎也可以工作...不确定这里什么是最佳实践! - Matthew Layton
1
@series0ne 你实际上可以在 std::string(或者最好是 const std::string&)和 const char* 上都有重载。 - Angew is no longer proud of SO
3
如果有人调用 Output::Print("Hello World"),但它被翻译成了Output::Print(bool value),与预期不符,你该如何强制出错或者"正确"(指预期的意思)地翻译它? - kirsche40
1
你知道在不同版本的C++中执行标准转换的决策是否有所不同吗? 即,C++17和C++98是否在相同情况下将const char *转换为bool执行标准转换? - Burgito
显示剩余4条评论

14

不确定为什么没有人发布这个,但是您可以添加另一个重载,将const char*转换为std::string。这样可以避免调用者担心此问题。

class Output
{
public:
    static void Print(bool value)
    {
        std::cout << value ? "True" : "False";
    }

    static void Print(std::string value)
    {
        std::cout << value;
    }

    // Just add the override that cast to std::string
    static void Print(const char* value)
    {
        Output::Print(std::string(value));
    }
};

1
我认为你的重载应该是 const char * value - Evan Hendler
1
已修复,谢谢Evan。 - Zachary Canann

10

如果您不想为const char*添加重载,可以使用模板解决此问题(如果可以使用模板),具体方法如下:

FWIW。

#include <iostream>
#include <string>
#include <type_traits>

template <typename Bool,
          typename T = std::enable_if_t<std::is_same<Bool, bool>{}>>
void foo(Bool)
{
  std::cerr << "bool\n";
}

void foo(const std::string&)
{
  std::cerr << "string\n";  
}

int main()
{
  foo("bar");
  foo(false);
}

3
自C++14起,我们拥有std::string_literals命名空间中的operator""s,可用于告诉编译器绑定到string(或在C++17中是string_view)重载函数:
using namespace std::string_literals;
Output::Print("Hello World"s);

输出:你好,世界


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