Строковый литерал соответствует перегрузке 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, поэтому совершенно новый для С++!
Ответы
Ответ 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));
}
};