В чем такое отличие x86 и x64 в VC++ 2019
Навеяно другим вопросом, пытаясь ответить на который, обнаружил такое непонятное мне поведение VC++ 2019.
Код:
#include <iostream>
using namespace std;
class String
{
public:
String(char* str):p(str){};
const char& operator[](size_t i) const { return p[i]; }
char& operator[](size_t i) { return p[i]; }
operator const char* () const { return p; }
operator char* () { return p; }
private:
char* p;
};
int main() {
char s[] = "123456";
String name = s;
std::cout << name[0] << std::endl;
name[1] = '5';
std::cout << name << std::endl;
}
На всякие возможные проблемы с памятью и иже с ними не смотрите, это просто урезанный до минимума код.
Так вот, при компиляции x64 строкой cl /EHsc main.cpp все проходит на ура.
А вот той же командой для x86 получаем
main.cpp
main.cpp(20): error C2666: String::operator []: для перегрузок (4) есть подобные преобразования
main.cpp(10): note: может быть "char &String::operator [](size_t)"
main.cpp(9): note: или "const char &String::operator [](size_t) const"
main.cpp(20): note: или "встроенный оператор C++[(const char *, int)"
main.cpp(20): note: или "встроенный оператор C++[(char *, int)"
main.cpp(20): note: при попытке сопоставить список аргументов "(String, int)"
main.cpp(21): error C2666: String::operator []: для перегрузок (4) есть подобные преобразования
main.cpp(10): note: может быть "char &String::operator [](size_t)"
main.cpp(9): note: или "const char &String::operator [](size_t) const"
main.cpp(21): note: или "встроенный оператор C++[(const char *, int)"
main.cpp(21): note: или "встроенный оператор C++[(char *, int)"
main.cpp(21): note: при попытке сопоставить список аргументов "(String, int)"
Кто-то может пояснить, почему такое отличие при компиляции под разные платформы?...
P.S. G++: https://ideone.com/TbDfC2
Ответы (1 шт):
g++ ведёт себя аналогично: g++ -m32 -c some.c++ -pedantic
some.c++: In function ‘int main()’:
some.c++:20:22: error: ambiguous overload for ‘operator[]’ (operand types are ‘String’ and ‘int’)
std::cout << name[0] << std::endl;
^
some.c++:20:22: note: candidate: operator[](const char*, int) <built-in>
some.c++:20:22: note: candidate: operator[](char*, int) <built-in>
some.c++:9:17: note: candidate: const char& String::operator[](size_t) const
const char& operator[](size_t i) const { return p[i]; }
^~~~~~~~
some.c++:10:11: note: candidate: char& String::operator[](size_t)
char& operator[](size_t i) { return p[i]; }
^~~~~~~~
some.c++:21:9: error: ambiguous overload for ‘operator[]’ (operand types are ‘String’ and ‘int’)
name[1] = '5';
^
some.c++:21:9: note: candidate: operator[](const char*, int) <built-in>
some.c++:21:9: note: candidate: operator[](char*, int) <built-in>
some.c++:9:17: note: candidate: const char& String::operator[](size_t) const
const char& operator[](size_t i) const { return p[i]; }
^~~~~~~~
some.c++:10:11: note: candidate: char& String::operator[](size_t)
char& operator[](size_t i) { return p[i]; }
^~~~~~~~```
32-х битный компилятор находит четыре варианта:
- Оставить тип
String, преобразоватьintвsize_t:char& String::operator[](size_t) - Оставить тип
String, преобразоватьintвsize_t:const char& String::operator[](size_t) const - Преобразовать тип
Stringвchar*, оставить типint:[char *, int] - Преобразовать тип
Stringвconst char*, оставить типint:[const char *, int]
Во всех четырех вариантах один тип преобразуется, второй нет. Поэтому компилятор не может выбрать лучший кандидат.
В 64-х битном случае ситуация иная: встроенный оператор [] имеет сигнатуру operator[](char*, long int)
Так как литерал 0 имеет тип int, то опции 3 и 4 из списка выше превращаются в
Преобразовать тип
Stringвchar*, преобразовать типintвlong int:[char *, long int]Преобразовать тип
Stringвconst char*, преобразовать типintвlong int:[const char *, long int]
Так как добавляется Promotion, который ухудшает кандидата, то компилятор отбрасывает эти кандидаты. Поэтому в 64-х битном случае компилируется без ошибок.
Чтобы запретить компилятору рассматривать встроенные операторы индексирования, явным образом сделайте литералы беззнаковыми: 0u и 5u. Тогда будет компилироваться и 64, и 32 бита.
PS. Тип встроенного оператора []
ISO C++ 2020, глава 12.7
16 For every cv-qualified or cv-unqualified object type T there exist candidate operator functions of the form ...
T & operator[](T *, std::ptrdiff_t);
То, что 64 битный g++ для ptrdiff_t использует long int, я установил экспериментально.