Подтвердить что ты не робот

Строковый литерал соответствует перегрузке bool вместо std::string

Я пытаюсь написать класс С++ с некоторыми перегруженными методами:

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");

это результат

True

Итак, почему, когда я определил, что метод может принимать значение boolean и string, использует ли он булевскую перегрузку, когда я передаю небулево значение?

EDIT: Я пришел из среды С#/Java, поэтому совершенно новый для С++!

4b9b3361

Ответ 1

"Hello World" - строковый литерал типа "array of 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"));

Ответ 2

FWIW, он может быть адресован таким образом (если шаблоны могут использоваться), если вы не хотите добавлять перегрузки для const char*.

#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

Не уверен, почему никто не опубликовал это, но вы можете добавить еще одну перегрузку, которая преобразует из 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));
    }
};