Строковый литерал соответствует логической перегрузке вместо 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");

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

Истинный

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

EDIT: я работаю в среде C#/Java, так что совершенно не знаком с C++!


person Matthew Layton    schedule 08.02.2013    source источник
comment
@meh, потому что они не являются функциями экземпляра.   -  person Matthew Layton    schedule 08.02.2013
comment
ваш const char* – это продвижение нативного типа до bool и повышение типа сконструированного значения до std::string. Что бы вы выбрали. ? Теперь угадайте, какой из них выбрал компилятор.   -  person WhozCraig    schedule 08.02.2013
comment
Вы передаете const char *, а не строку, попробуйте Output::Print(std::string(Hello World))   -  person jmetcalfe    schedule 08.02.2013
comment
Что касается статики: в C++ функции могут быть свободны от тирании системы классов, поэтому вам не нужно создавать квазиклассы, как в Java.   -  person molbdnilo    schedule 08.02.2013
comment
@molbdnilo, да, я знаю, что у вас могут быть бесклассовые функции, немного похожие на JavaScript, я думаю, где функции не нужно привязывать к прототипу... опять же, поскольку я новичок в C++, я не уверен, что это лучшая практика здесь.   -  person Matthew Layton    schedule 08.02.2013


Ответы (4)


"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"));
person Joseph Mansfield    schedule 08.02.2013
comment
@LuchianGrigore Я согласен, что это более глубокий вопрос. Я просто не уверен, что ОП вообще знает, что он спросил об этом = P - person WhozCraig; 08.02.2013
comment
Да, я попробовал это, и это сработало... просто кажется неопрятным! Я изменил объявление метода на Print(const char* value), которое, похоже, тоже работает... Хотя не уверен, что здесь лучше всего! - person Matthew Layton; 08.02.2013
comment
@LuchianGrigore Я бросил это туда. - person Joseph Mansfield; 08.02.2013
comment
Да, видел это, гораздо лучше, если вы спросите меня. +1 - person Luchian Grigore; 08.02.2013
comment
@ series0ne На самом деле у вас могут быть обе перегрузки - на std::string (или предпочтительно на const std::string&) и на const char*. - person Angew is no longer proud of SO; 08.02.2013
comment
Как вызвать ошибку или правильный (в смысле ожидаемый) перевод, если кто-то называет Output::Print("Hello World"), который переводится в Output::Print(bool value), чего никто не ожидает? - person kirsche40; 17.02.2014
comment
Является ли это тем случаем, когда то, что Стандарт считает лучшим, и то, что считает лучшим J. Random User, полностью расходятся друг с другом? (Извините, риторический вопрос. Просто я не уверен, что J. Random User здесь не прав.) - person Steve Summit; 21.08.2018
comment
@kirsche40 Шаблоны и SFINAE. - person Deduplicator; 05.12.2018
comment
Знаете ли вы, есть ли разница в решении о выполнении стандартного преобразования между разными версиями C++? то есть Будут ли C++17 и C++98 выполнять стандартное преобразование из const char * в bool в одних и тех же случаях? - person Burgito; 24.01.2020

Не уверен, почему никто не опубликовал это, но вы можете добавить еще одну перегрузку, которая преобразует 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));
    }
};
person Zachary Canann    schedule 05.12.2018
comment
Я думаю, вы имеете в виду const char * value для своей перегрузки. - person Evan Hendler; 26.10.2020
comment
Исправлено, Тай Эван. - person Zachary Canann; 26.10.2020

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);
}
person akim    schedule 16.03.2017

Начиная с C++14 у нас есть operator""s из пространства имен std::string_literals, которое можно использовать, чтобы сообщить компилятору о привязке к перегрузке string (или string_view в C++17):

using namespace std::string_literals;
Output::Print("Hello World"s);

Отпечатки: Hello World

person Замфир Йончев    schedule 16.01.2021