|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
По мотивам топика про шаблонную магию. Я понял, что я ничего не понял. Второй день читаю стандарт плюсов, на английском. Опух. Я всегда думал, что c-cast компилятор переводит в reinterpret_cast. Но тут в процессе чтения стандарта и прочих статей выяснилось , что это далеко не так. И у меня до сих пор вопросы, которые мне не удалось нагуглить, или я пока не дошёл до них в стандарте(если они там есть). 1. По каким правилам строятся касты (константных) ссылок? Т.е. Код: plaintext 1. 2. 3. 4. 5. 6. 7.
Почему всё оно так? 2. Получается, что операторы string(), string&(), const string&() из класса А игнорируются? Для чего они тогда нужны. С простыми типами ситуация ровно такая же, только const int&() не падает (потому что переменные в А так расположены, видимо). Судя по ассемблеру, на любые касты (value, &, const&, &&) любых вещей (lvalue string, prvalue const char*), вызываются конструкторы string, и всё работает ок. С классом А тоже самое, исключение string&() - там зовётся string::operator =(string&) Где доходчиво почитать по всем тонкостям каста? cv, reference/pointer, compound/POD типы, с операторами и без? Хочется просветления. ... |
|||
:
Нравится:
Не нравится:
|
|||
09.07.2019, 13:37 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
CEMb, Правил много. Никто их все не помнит )) Но вот например кое-какие простые, которыми в большинстве случаев можно руководствоваться: Если существует static_cast/const_cast между типами (конструктор/оператор или встроенный для чисел), то будет использован он. Если нет, то будет применен reinterpret_cast. Он сработает для POD (числа, ссылки, указатели и структуры без конструкторов). А (std::string)a сработает только если есть конструкторы/операторы преобразования. ЗЫ. Ну и собственно главное. Не надо вообще С-каст использовать, особенно с классами. ... |
|||
:
Нравится:
Не нравится:
|
|||
09.07.2019, 19:55 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
Anatoly MoskovskyНе надо вообще С-каст использовать, особенно с классами. Да, если он сработает как reinterpret_cast - будет больно. Posted via ActualForum NNTP Server 1.5 ... |
|||
:
Нравится:
Не нравится:
|
|||
09.07.2019, 21:14 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
CEMbПо мотивам топика про шаблонную магию. Я понял, что я ничего не понял. Второй день читаю стандарт плюсов, на английском. Опух. Я всегда думал, что c-cast компилятор переводит в reinterpret_cast. Но тут в процессе чтения стандарта и прочих статей выяснилось , что это далеко не так. И у меня до сих пор вопросы, которые мне не удалось нагуглить, или я пока не дошёл до них в стандарте(если они там есть). 1. По каким правилам строятся касты (константных) ссылок? https://timsong-cpp.github.io/cppwp/n4659/dcl.init.ref][dcl.init.ref] CEMbТ.е. Код: plaintext 1. 2. 3. 4. 5. 6. 7.
Почему всё оно так?Ответить на это мы должны конечно не видя что внутри `class A`. ... |
|||
:
Нравится:
Не нравится:
|
|||
10.07.2019, 11:08 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
a.guestОтветить на это мы должны конечно не видя что внутри `class A`. Ну вот в классе A есть три оператора: Код: plaintext 1. 2. 3.
в коде Код: plaintext 1.
почему зовётся operator const T&()? ... |
|||
:
Нравится:
Не нравится:
|
|||
11.07.2019, 13:42 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
CEMb, Код: plaintext 1.
Шаблон может быть невалидным для конкретного аргумента и тогда он через SFINAE убирается из компиляции без ошибок относящихся к этому шаблону. Поэтому не мешало бы код все-таки привести такой чтобы можно было не допиливая его скопировать в IDE и откомпилировать. ... |
|||
:
Нравится:
Не нравится:
|
|||
11.07.2019, 18:05 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
CEMba.guestОтветить на это мы должны конечно не видя что внутри `class A`. Ну вот в классе A есть три оператора: Код: plaintext 1. 2. 3.
в коде Код: plaintext 1.
почему зовётся operator const T&()?Это в студии зовётся. В clang зовётся operator T(), в gcc — ошибка из-за неоднозначности. Сейчас нет времени разбираться, кто из них правее, но, предварительно, похоже, что gcc. ... |
|||
:
Нравится:
Не нравится:
|
|||
13.07.2019, 14:25 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
Anatoly MoskovskyCEMb, Код: plaintext 1.
Шаблон может быть невалидным для конкретного аргумента и тогда он через SFINAE убирается из компиляции без ошибок относящихся к этому шаблону. Поэтому не мешало бы код все-таки привести такой чтобы можно было не допиливая его скопировать в IDE и откомпилировать.Опять специалисты набежали в тред... При ошибке в теле функции будет ошибка компиляции, а не исключение шаблона из списка кандидатов. ... |
|||
:
Нравится:
Не нравится:
|
|||
13.07.2019, 14:30 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
a.guestОпять специалисты набежали в тред... При ошибке в теле функции будет ошибка компиляции, а не исключение шаблона из списка кандидатов. А, ну да. Ну это не отменяет необходимости постить код целиком. ... |
|||
:
Нравится:
Не нравится:
|
|||
15.07.2019, 11:10 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
Что-то у меня мозг замылился. С-cast и неявный каст - их перепутал я <-_->. Я немного позже вернусь к теме. Пока просто всё починил "интуитивно" и обложился тестами. Потом хочу просто выложить сюда примеры всяких кастов с описаниями (не)сгенерённого кода. ... |
|||
:
Нравится:
Не нравится:
|
|||
16.07.2019, 12:24 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
a.guestCEMbпропущено... Ну вот в классе A есть три оператора: Код: plaintext 1. 2. 3.
в коде Код: plaintext 1.
почему зовётся operator const T&()?Это в студии зовётся. В clang зовётся operator T(), в gcc — ошибка из-за неоднозначности. Сейчас нет времени разбираться, кто из них правее, но, предварительно, похоже, что gcc.Праведный друг внезапно прав. Примеры с правилами приведения типов в шаблонах (а правила в шаблонах свои) и именно с ловушками описаны у Мейерса в Effective Modern C++ 11/14 ... |
|||
:
Нравится:
Не нравится:
|
|||
16.07.2019, 23:40 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
SiemarglПримеры с правилами приведения типов в шаблонах (а правила в шаблонах свои) и именно с ловушками описаны у Мейерса в Effective Modern C++ 11/14Ну и какое поведение правильно по Мейерсу? ... |
|||
:
Нравится:
Не нравится:
|
|||
17.07.2019, 13:59 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
a.guest, выбор параметра как T& или как const T& - равнозначен. Исправленный пример https://ideone.com/XaSy15 Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29.
А когда в дело идут T&&, вообще хоть вешайся =) ... |
|||
:
Нравится:
Не нравится:
|
|||
17.07.2019, 17:53 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
Siemargla.guest, выбор параметра как T& или как const T& - равнозначен. Исправленный пример https://ideone.com/XaSy15 Не компилируется начиная с GCC 8 (-std=c++14), неоднозначность в `s = (string)a; // uncompilible . fixed by (*)`. В clang тоже неоднозначность с -std=c++14. (Компилируется с -std=c++17). Кто прав или не прав и почему? ... |
|||
:
Нравится:
Не нравится:
|
|||
17.07.2019, 18:28 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
a.guest, Если быть точным, и верить godbolt, то gcc 8.3 еще компилируется, а вот 9.1 уже нет Проблема начинается раньше - в этой строке на самом деле вызывается operator T&() (а не T()) (1), и компилятор уже пытается выбрать между конструктором из T& и вновь появившимся конструктором из T&& (2) Проблему (2), похоже решили в стандарте С++17 По поводу (1) у меня нет понятного решения - при выборе между operator T&() и operator T() всегда выбирается первый, даже если писать expicit и приводить static_cast'ом ... |
|||
:
Нравится:
Не нравится:
|
|||
17.07.2019, 20:12 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
Собственно предлагается выделять operator T() const, поскольку он должен создавать новый тип, не меняя себя. Но это способ обхода, а не причина. ... |
|||
:
Нравится:
Не нравится:
|
|||
17.07.2019, 20:24 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
SiemarglЕсли быть точным, и верить godbolt, то gcc 8.3 еще компилируется, а вот 9.1 уже нетДа, начиная с GCC 9, не 8. SiemarglПроблема начинается раньше - в этой строке на самом деле вызывается operator T&() (а не T()) (1), и компилятор уже пытается выбрать между конструктором из T& и вновь появившимся конструктором из T&& (2)Если бы выбирался operator T&(), то move-constructor не рассматривался бы. SiemarglПроблему (2), похоже решили в стандарте С++17Я думаю то, что clang принимает этот код — баг clang-а. SiemarglПо поводу (1) у меня нет понятного решения - при выборе между operator T&() и operator T() всегда выбирается первый, даже если писать expicit и приводить static_cast'омВ каком смысле "всегда выбирается operator T&()"? ... |
|||
:
Нравится:
Не нравится:
|
|||
17.07.2019, 20:35 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
SiemarglИсправленный пример https://ideone.com/XaSy15 бл?*:!... Только сейчас заметил... Нахер ты из шаблонных операторов каста сделал шаблонным класс? ... |
|||
:
Нравится:
Не нравится:
|
|||
17.07.2019, 20:41 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
a.guestSiemarglПроблема начинается раньше - в этой строке на самом деле вызывается operator T&() (а не T()) (1), и компилятор уже пытается выбрать между конструктором из T& и вновь появившимся конструктором из T&& (2)Если бы выбирался operator T&(), то move-constructor не рассматривался бы. не угадал #1 with x86-64 gcc 9.1 <source>: In function 'int main()': <source>:19:14: error: call of overloaded 'basic_string(A<std::__cxx11::basic_string<char> >&)' is ambiguous 19 | s = (string)a; // uncompilible . fixed by (*) | ^ In file included from /opt/compiler-explorer/gcc-9.1.0/include/c++/9.1.0/string:55, from /opt/compiler-explorer/gcc-9.1.0/include/c++/9.1.0/bits/locale_classes.h:40, from /opt/compiler-explorer/gcc-9.1.0/include/c++/9.1.0/bits/ios_base.h:41, from /opt/compiler-explorer/gcc-9.1.0/include/c++/9.1.0/ios:42, from /opt/compiler-explorer/gcc-9.1.0/include/c++/9.1.0/ostream:38, from /opt/compiler-explorer/gcc-9.1.0/include/c++/9.1.0/iostream:39, from <source>:1: /opt/compiler-explorer/gcc-9.1.0/include/c++/9.1.0/bits/basic_string.h:552:7: note: candidate: 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>:: basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&& ) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' 552 | basic_string(basic_string&& __str) noexcept | ^~~~~~~~~~~~ /opt/compiler-explorer/gcc-9.1.0/include/c++/9.1.0/bits/basic_string.h:448:7: note: candidate: 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' 448 | basic_string(const basic_string& __str) a.guestSiemarglПо поводу (1) у меня нет понятного решения - при выборе между operator T&() и operator T() всегда выбирается первый, даже если писать expicit и приводить static_cast'омВ каком смысле "всегда выбирается operator T&()"? Если в ideone запустить, то видно, что выбирается приведение к ссылке и в первом случае( Моя мысль в том, что basic_string имеет конструктор от ссылки на строку, и от него пляшут. a.guestSiemarglИсправленный пример https://ideone.com/XaSy15 бл?*:!... Только сейчас заметил... Нахер ты из шаблонных операторов каста сделал шаблонным класс? Не имеет разницы. Но мне просто нужна была статическая переменная, чтобы вернуть ссылку на что то живое =) Я нашел объяснение, но не очень то понятное. https://stackoverflow.com/questions/53101121/c17-explicit-conversion-function-vs-explicit-constructor-implicit-conversio?rq=1 ... |
|||
:
Нравится:
Не нравится:
|
|||
17.07.2019, 21:55 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
Siemargla.guestпропущено... Если бы выбирался operator T&(), то move-constructor не рассматривался бы. не угадалУдали operator T(), и неоднозначность пропадёт. Siemargla.guestпропущено... В каком смысле "всегда выбирается operator T&()"? Если в ideone запустить, то видно, что выбирается приведение к ссылке и в первом случае( Или, как выяснили выше, выбирается не всегда, а только в определённых версиях компиляторов. SiemarglНе имеет разницы. Но мне просто нужна была статическая переменная, чтобы вернуть ссылку на что то живое =)Ну вообще-то имеет. SiemarglЯ нашел объяснение, но не очень то понятное. https://stackoverflow.com/questions/53101121/c17-explicit-conversion-function-vs-explicit-constructor-implicit-conversio?rq=1 Буду разбираться позже. Но вообще я не совсем понимаю, почему в C++17 должно работать. Как т.н. guaranteed copy elision что-то меняет. Неоднозначность должна быть из-за каста. Сишный каст `(string)x` эквивалентен static_cast. static_cast к не-ссылочному типу определён как direct initialization объекта целевого типа выражением-аргументом каста `e` и возможен, если существуе implicit conversion sequence от типа выражения к целевому типу. Вообще implicit conversion sequence определено как последовательность преобразований, применяемых при вызове функции с параметром целевого типа с выражением-аргументом `e`. Тут уже кривость стандарта, т.к. инициализация параметра при вызове — это copy-initialization, а каст определён как direct initialization. Впрочем, это известный баг . ... |
|||
:
Нравится:
Не нравится:
|
|||
17.07.2019, 23:33 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
Siemarglвыбор параметра как T& или как const T& - равнозначен.Вот это отдельный вопрос, почему так? У меня, например, сейчас такая проблема: я сделал контейнер с параметрами, у которых данные - это _variant_t. С возвращением POD-типов всё ок, но когда надо вернуть string из _bstr_t, начинаются проблемы. В том числе и с граблями, типа static T t; И ладно, когда надо вернуть ссылку на что-то нулевое. А вот когда надо через статическую функцию вернуть константную ссылку (из константного же оператора, sic) - у меня руки не поворачиваются такое сделать :( a.guestСишный каст `(string)x` эквивалентен static_cast Если быть совсем точным, то https://en.cppreference.com/w/cpp/language/explicit_cast ... |
|||
:
Нравится:
Не нравится:
|
|||
18.07.2019, 05:37 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
SiemarglМоя мысль в том, что basic_string имеет конструктор от ссылки на строку, и от него пляшут.Собственно так и есть, приведение типа вызывается такое, какое нужно последующему конструктору. Если подходит несколько комбинаций (конструктор+приведение) - будет неоднозначность. Заменяем в примере выше string на int и тут же получаем неоднозначности. ... |
|||
:
Нравится:
Не нравится:
|
|||
18.07.2019, 09:18 |
|
Cast. Cook book.
|
|||
---|---|---|---|
#18+
Тут есть ещё один тонкий момент: когда вы явно кастуете в ссылку, компилятор (по крайней мере, MS) не пытается делать преобразование типа. Он просто сразу считает, что то, что справа от каста - ссылка. Это везде так или только на шаблонных операторах каста? ... |
|||
:
Нравится:
Не нравится:
|
|||
18.07.2019, 12:24 |
|
|
start [/forum/topic.php?fid=57&gotonew=1&tid=2017596]: |
0ms |
get settings: |
10ms |
get forum list: |
14ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
41ms |
get topic data: |
10ms |
get first new msg: |
8ms |
get forum data: |
3ms |
get page messages: |
59ms |
get tp. blocked users: |
2ms |
others: | 266ms |
total: | 421ms |
0 / 0 |