Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / Cast. Cook book. / 23 сообщений из 23, страница 1 из 1
09.07.2019, 13:37
    #39835457
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
По мотивам топика про шаблонную магию. Я понял, что я ничего не понял. Второй день читаю стандарт плюсов, на английском. Опух.

Я всегда думал, что c-cast компилятор переводит в reinterpret_cast. Но тут в процессе чтения стандарта и прочих статей выяснилось , что это далеко не так. И у меня до сих пор вопросы, которые мне не удалось нагуглить, или я пока не дошёл до них в стандарте(если они там есть).

1. По каким правилам строятся касты (константных) ссылок? Т.е.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
class A {...};
string s;
A a;
s = (string)a;            // uncompilible
s = a.operator std::string(); // works
s = (string&)a;          // wokrs right too
s = (const string&)a; // fails and ambigious

Почему всё оно так?

2. Получается, что операторы string(), string&(), const string&() из класса А игнорируются? Для чего они тогда нужны. С простыми типами ситуация ровно такая же, только const int&() не падает (потому что переменные в А так расположены, видимо).
Судя по ассемблеру, на любые касты (value, &, const&, &&) любых вещей (lvalue string, prvalue const char*), вызываются конструкторы string, и всё работает ок. С классом А тоже самое, исключение string&() - там зовётся string::operator =(string&)

Где доходчиво почитать по всем тонкостям каста? cv, reference/pointer, compound/POD типы, с операторами и без? Хочется просветления.
...
Рейтинг: 0 / 0
09.07.2019, 19:55
    #39835685
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
CEMb,

Правил много. Никто их все не помнит ))

Но вот например кое-какие простые, которыми в большинстве случаев можно руководствоваться:
Если существует static_cast/const_cast между типами (конструктор/оператор или встроенный для чисел), то будет использован он.
Если нет, то будет применен reinterpret_cast. Он сработает для POD (числа, ссылки, указатели и структуры без конструкторов).
А (std::string)a сработает только если есть конструкторы/операторы преобразования.

ЗЫ. Ну и собственно главное. Не надо вообще С-каст использовать, особенно с классами.
...
Рейтинг: 0 / 0
09.07.2019, 21:14
    #39835704
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
Anatoly MoskovskyНе надо вообще С-каст использовать, особенно с классами.

Да, если он сработает как reinterpret_cast - будет больно.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
10.07.2019, 11:08
    #39835859
a.guest
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
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 {...};
string s;
A a;
s = (string)a;            // uncompilible
s = a.operator std::string(); // works
s = (string&)a;          // wokrs right too
s = (const string&)a; // fails and ambigious

Почему всё оно так?Ответить на это мы должны конечно не видя что внутри `class A`.
...
Рейтинг: 0 / 0
11.07.2019, 13:42
    #39836361
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
a.guestОтветить на это мы должны конечно не видя что внутри `class A`.
Ну вот в классе A есть три оператора:
Код: plaintext
1.
2.
3.
template <typename T> operator T() {...}
template <typename T> operator T&() {...}
template <typename T> operator const T&() {...}


в коде
Код: plaintext
1.
s = (string)a;

почему зовётся operator const T&()?
...
Рейтинг: 0 / 0
11.07.2019, 18:05
    #39836520
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
CEMb,

Код: plaintext
1.
template <typename T> operator T() {...}


Шаблон может быть невалидным для конкретного аргумента и тогда он через SFINAE убирается из компиляции без ошибок относящихся к этому шаблону.

Поэтому не мешало бы код все-таки привести такой чтобы можно было не допиливая его скопировать в IDE и откомпилировать.
...
Рейтинг: 0 / 0
13.07.2019, 14:25
    #39837083
a.guest
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
CEMba.guestОтветить на это мы должны конечно не видя что внутри `class A`.
Ну вот в классе A есть три оператора:
Код: plaintext
1.
2.
3.
template <typename T> operator T() {...}
template <typename T> operator T&() {...}
template <typename T> operator const T&() {...}


в коде
Код: plaintext
1.
s = (string)a;

почему зовётся operator const T&()?Это в студии зовётся. В clang зовётся operator T(), в gcc — ошибка из-за неоднозначности. Сейчас нет времени разбираться, кто из них правее, но, предварительно, похоже, что gcc.
...
Рейтинг: 0 / 0
13.07.2019, 14:30
    #39837085
a.guest
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
Anatoly MoskovskyCEMb,

Код: plaintext
1.
template <typename T> operator T() {...}


Шаблон может быть невалидным для конкретного аргумента и тогда он через SFINAE убирается из компиляции без ошибок относящихся к этому шаблону.

Поэтому не мешало бы код все-таки привести такой чтобы можно было не допиливая его скопировать в IDE и откомпилировать.Опять специалисты набежали в тред... При ошибке в теле функции будет ошибка компиляции, а не исключение шаблона из списка кандидатов.
...
Рейтинг: 0 / 0
15.07.2019, 11:10
    #39837361
Anatoly Moskovsky
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
a.guestОпять специалисты набежали в тред... При ошибке в теле функции будет ошибка компиляции, а не исключение шаблона из списка кандидатов.
А, ну да.
Ну это не отменяет необходимости постить код целиком.
...
Рейтинг: 0 / 0
16.07.2019, 12:24
    #39837832
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
Что-то у меня мозг замылился. С-cast и неявный каст - их перепутал я <-_->.
Я немного позже вернусь к теме. Пока просто всё починил "интуитивно" и обложился тестами. Потом хочу просто выложить сюда примеры всяких кастов с описаниями (не)сгенерённого кода.
...
Рейтинг: 0 / 0
16.07.2019, 23:40
    #39838100
Siemargl
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
a.guestCEMbпропущено...

Ну вот в классе A есть три оператора:
Код: plaintext
1.
2.
3.
template <typename T> operator T() {...}
template <typename T> operator T&() {...}
template <typename T> operator const T&() {...}


в коде
Код: plaintext
1.
s = (string)a;

почему зовётся operator const T&()?Это в студии зовётся. В clang зовётся operator T(), в gcc — ошибка из-за неоднозначности. Сейчас нет времени разбираться, кто из них правее, но, предварительно, похоже, что gcc.Праведный друг внезапно прав.
Примеры с правилами приведения типов в шаблонах (а правила в шаблонах свои) и именно с ловушками описаны у Мейерса в Effective Modern C++ 11/14
...
Рейтинг: 0 / 0
17.07.2019, 13:59
    #39838301
a.guest
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
SiemarglПримеры с правилами приведения типов в шаблонах (а правила в шаблонах свои) и именно с ловушками описаны у Мейерса в Effective Modern C++ 11/14Ну и какое поведение правильно по Мейерсу?
...
Рейтинг: 0 / 0
17.07.2019, 17:53
    #39838426
Siemargl
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
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.
#include <iostream>
using namespace std;

template <typename T> class A {
	string a;
	static T t;
public:	
	A(): a("void\n"){};
	operator T() { a = "T\n"; return T(a); }
	operator T&() { a = "ref T\n"; t = a; return t; }
//	operator const T&() { a = "const ref T\n"; t= a; return const_cast<const T&>(t); }	  (*) FIX
};

template <> string A < string >::t = "zero";

int main() {
	string s;
	A<string> a;
	s = (string)a;            // uncompilible . fixed by (*)
	cout << 1 << s;
	s = a.operator std::string(); // works
	cout << 2 << s;
	s = (string&)a;          // wokrs right too
	cout << 3 << s;
	s = (const string&)a; // fails and ambigious . fixed by (*)
	cout << 4 << s;

	return 0;
}


А когда в дело идут T&&, вообще хоть вешайся =)
...
Рейтинг: 0 / 0
17.07.2019, 18:28
    #39838437
a.guest
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
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).

Кто прав или не прав и почему?
...
Рейтинг: 0 / 0
17.07.2019, 20:12
    #39838459
Siemargl
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
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'ом
...
Рейтинг: 0 / 0
17.07.2019, 20:24
    #39838466
Siemargl
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
Собственно предлагается выделять operator T() const, поскольку он должен создавать новый тип, не меняя себя.

Но это способ обхода, а не причина.
...
Рейтинг: 0 / 0
17.07.2019, 20:35
    #39838471
a.guest
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
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&()"?
...
Рейтинг: 0 / 0
17.07.2019, 20:41
    #39838473
a.guest
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
SiemarglИсправленный пример https://ideone.com/XaSy15 бл?*:!... Только сейчас заметил...
Нахер ты из шаблонных операторов каста сделал шаблонным класс?
...
Рейтинг: 0 / 0
17.07.2019, 21:55
    #39838483
Siemargl
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
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
...
Рейтинг: 0 / 0
17.07.2019, 23:33
    #39838513
a.guest
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
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.
Впрочем, это известный баг .
...
Рейтинг: 0 / 0
18.07.2019, 05:37
    #39838532
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
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
...
Рейтинг: 0 / 0
18.07.2019, 09:18
    #39838571
Siemargl
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
SiemarglМоя мысль в том, что basic_string имеет конструктор от ссылки на строку, и от него пляшут.Собственно так и есть, приведение типа вызывается такое, какое нужно последующему конструктору.
Если подходит несколько комбинаций (конструктор+приведение) - будет неоднозначность.

Заменяем в примере выше string на int и тут же получаем неоднозначности.
...
Рейтинг: 0 / 0
18.07.2019, 12:24
    #39838709
CEMb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Cast. Cook book.
Тут есть ещё один тонкий момент: когда вы явно кастуете в ссылку, компилятор (по крайней мере, MS) не пытается делать преобразование типа. Он просто сразу считает, что то, что справа от каста - ссылка.
Это везде так или только на шаблонных операторах каста?
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / Cast. Cook book. / 23 сообщений из 23, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]