Сравнение строковой переменной с явным значением char*

Я не понимаю, почему этот код компилируется и запускается:

std::string s;
std::cin >> s;
// if (s == "done") {     // version 1
if ("done" == s) {        // version 2
    std::cout << "We're done here" << std::endl;
}

Версия 1 работает так, как я и ожидал. Компилятор видит, что s является std::string, и использует std::string определение == для сравнения.

Однако, сравнивая переменную с явным значением, я предпочитаю использовать трюк, помещая явное значение первым на тот случай, если однажды я случайно использую = вместо этого и вместо этого выполняю присваивание. Следовательно, версия 2.

Теперь версия 2 работает на моем компиляторе (llvm в MacOS) так же, как и версия 1, но я не уверен, почему (и является ли это надежным результатом). Я бы хотел, чтобы компилятор увидел «выполнено» как явное значение char* (литерал) и сказал: «Эй, == не имеет смысла для char *» и выдал бы мне сообщение об ошибке компиляции. Но мой компилятор этого не делает, он компилируется без нареканий, и код выполняется так же, как и в версии 1.

Что я здесь неправильно понимаю?

Знаете ли вы о operator== и , как это работает ?

tadman 19.02.2023 20:34

Если вы включите предупреждения, компилятор предупредит вас, если вы сделаете if (x = 1), когда собирались сделать if (x == 1). Не нужно коверкать код.

Eljay 19.02.2023 20:35
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
74
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Тип "done" не char*. Это const char[5].

Но в любом случае это работает, потому что если вы включаете <string>, который вы должны использовать для std::string, то (до C++20) вы включаете перегрузку для operator== формы

template< class CharT, class Traits, class Alloc >
bool operator==( const std::basic_string<CharT,Traits,Alloc>& lhs,
                 const CharT* rhs );

и один из видов

template< class CharT, class Traits, class Alloc >
bool operator==( const CharT* lhs,
                 const std::basic_string<CharT,Traits,Alloc>& rhs );

См. https://en.cppreference.com/w/cpp/string/basic_string/operator_cmp для справки.

std::string — это просто std::basic_string, где CharT — это char, а Traits и Alloc — некоторые значения по умолчанию, которые здесь не имеют значения.

Таким образом, одна перегрузка принимает const std::string& в качестве левого аргумента и const char* в качестве правого аргумента, а другая принимает обратное.

const char[N] можно вывести как const char*, и оно неявно преобразуется в последнее для каждого N, поэтому первая перегрузка возможна для s == "done", а вторая — для "done" == s.

Стандартная библиотека специально написана с этими перегрузками, чтобы вы могли ее использовать. Ваш подход к использованию варианта "done" == s имеет смысл, потому что "done" = s действительно будет ошибкой. operator= может быть перегружен только типом класса в левой части.

Начиная с C++20, перегрузки выглядят немного иначе. В частности, больше нет необходимости иметь оба. Компилятор теперь автоматически пытается перегружаться, соответствующие переписанному выражению с обратными операндами ==, при разрешении перегрузки.


к явному значению,

явная константа

Я не уверен, что вы имеете в виду здесь, но «явное значение» и «явная константа» не являются стандартной терминологией. Вероятно, вместо этого вы имеете в виду «(строковый) литерал».

и говорит: "Эй, == не имеет смысла для char*"

Это не работает таким образом. Как только любая сторона == является типом класса, компилятор должен учитывать, что == может быть перегружен для соответствия выражению.

«Как только любая сторона == является типом класса, компилятор должен учитывать, что == может быть перегружен для соответствия выражению». Ага, у меня было ошибочное впечатление, что это всегда был первый (крайний левый) встречающийся операнд, который определял, где искать определение. Спасибо!

kw86 19.02.2023 21:58

Для шаблона класса std::basic_string оператор равенства == перегружен, в частности, следующим образом

template<class charT, class traits, class Allocator>
bool operator==(const charT* lhs, const basic_string<charT, traits, Allocator>& rhs);

Таким образом, первый аргумент может быть строковым литералом C без необходимости какого-либо преобразования (кроме стандартного неявного преобразования типа массива в указатель на тип элемента массива).

На самом деле у оператора есть три перегрузки

template<class charT, class traits, class Allocator>
bool operator==(const basic_string<charT, traits, Allocator>& lhs,
const basic_string<charT, traits, Allocator>& rhs) noexcept;

template<class charT, class traits, class Allocator>
bool operator==(const charT* lhs, const basic_string<charT, traits, Allocator>& rhs);

и

template<class charT, class traits, class Allocator>
bool operator==(const basic_string<charT, traits, Allocator>& lhs,
const charT* rhs);

Другие вопросы по теме