Я не понимаю, почему этот код компилируется и запускается:
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.
Что я здесь неправильно понимаю?
Если вы включите предупреждения, компилятор предупредит вас, если вы сделаете if (x = 1)
, когда собирались сделать if (x == 1)
. Не нужно коверкать код.
Тип "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*"
Это не работает таким образом. Как только любая сторона ==
является типом класса, компилятор должен учитывать, что ==
может быть перегружен для соответствия выражению.
«Как только любая сторона == является типом класса, компилятор должен учитывать, что == может быть перегружен для соответствия выражению». Ага, у меня было ошибочное впечатление, что это всегда был первый (крайний левый) встречающийся операнд, который определял, где искать определение. Спасибо!
Для шаблона класса 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);
Знаете ли вы о
operator==
и , как это работает ?