Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.141.100.120] |
|
Страницы: (495) « Первая ... 492 493 [494] 495 ( Перейти к последнему сообщению ) |
Сообщ.
#7396
,
|
|
|
Все можно назвать синтаксическим сахаром, кроме ассемблера. Да и там он есть.
|
Сообщ.
#7397
,
|
|
|
Сообщ.
#7398
,
|
|
|
Цитата D_KEY @ После отработки вызываемого конструктора у тебя будет готовый объект со всеми инициализированными полями. Или я ошибаюсь и тут? Нет, не ошибаешься. Я о том, что ты не можешь вызвать метод, пока не отработал список инициализации, делегирующий же конструктор именно частью списка инициализации и является. Добавлено Цитата D_KEY @ Виртуальные методы вводят новую концепцию динамической диспетчеризации метода по типу объекта. Что на практике всего лишь указатели на функции - можно сделать руками. |
Сообщ.
#7399
,
|
|
|
Цитата MyNameIsIgor @ делегирующий же конструктор именно частью списка инициализации и является. Так ведь чисто синтаксически. Объект-то полностью проинициализирован будет после его вызова. |
Сообщ.
#7400
,
|
|
|
Цитата D_KEY @ Так ведь чисто синтаксически. Объект-то полностью проинициализирован будет после его вызова. Так в том то и дело, что после. Потому и нельзя заменить на метод, т.к. тогда у нас объект частично должен быть сконструирован до вызова. Добавлено D_KEY, вот код struct test { int& i; std::string s; test(int& i) : test(i, std::string()) {} test(int& i, std::string s) : i(i), s(std::move(s)) {} }; Замени на метод. |
Сообщ.
#7401
,
|
|
|
Цитата MyNameIsIgor @ Отнюдь. Метод не обязан полагаться на контракты. Да, это плохо, но в каждом классе есть хотя бы один такой, собственно конструктор (иногда неявный), так что считать ли некий метод (не конструктор) специальным, личное дело прогаммера. Впрочем, на эту тему я писал не раз, не буду повторяться. Там один итог в итоге: такие методы должны быть приватные. Собственно делегируемые конструкторы по ряду причин тоже.Метод требует, чтобы все поля класса были сконструированы, делегирующий конструктор - нет. Цитата MyNameIsIgor @ Т.е. таки сахар. Вместо макросов подойдут и inline. Даже constexpr, если есть возможность.Я подумаю... Не очень хорошо знаю пользовательские литералы. Но как минимум - засорение глобального пространства имён. Цитата MyNameIsIgor @ Не новая, улучшенная старая, которую многие компиляторы и так предоставляли, так что теперь она стандартизирована.Полагаться на это можно, но потребовать её какими бы то ни было методами вы не можете. Следовательно, это новая функциональность, а не сокращённая запись старой. Цитата MyNameIsIgor @ Это прекрасно делалось мааааленькой модификацией семантики throw-спецификаторов.Нет. Я могу написать template<class T> void foo(T t) noexcept(noexcept(T(t)) { /*...*/ } И вообще, noexept(expression) - это константное выражение, которое я могу использовать, например, при выборе специализации шаблона. Но тут надо отметить, что throw()-спецификаторы себя не оправдали. Так что на лицо не столько сахар, сколько мотивация к отказу от старой семантики. Цитата MyNameIsIgor @ Вот и я об этом. Коли исключение произошло, его требуется донести. Зачем к чему тогда ещё одно новое? Только ради замены. Тогда зачем доносить исходное, если архитектурно оно должно быть заменено?Цитата Qraizer @ std::nested_exception - не заменяется, но непонятно, а занафик нужно, окромя редчайших моментов отладки Нужно, чтобы донести до обработчика первичное исключение, если оно пролетает через несколько слоёв архитектуры, и залогировать его, чтобы знать первопричину. В общем, я не вижу места этой фиче в продакшне. Но я оговорился, что тут могу ошибаться. Добавлено Цитата D_KEY @ Ум-м-м... до меня только что дошло. После отработки делегируемого объект-то уже будет иметь свой собственный динамический тип, ведь так? Так что не виртуальные конструкторы, "о котором так много говорили ©" дельфисты, но-таки полноформатный полиморфизм в делегирующем конструкторе мы вполне получаем. Однако, во-первых, нет симметрии с деструкторами, во-вторых, ... ну были ж фабрики. Так ведь чисто синтаксически. Объект-то полностью проинициализирован будет после его вызова. |
Сообщ.
#7402
,
|
|
|
Цитата Qraizer @ Отнюдь. Ну, тогда измените мой пример. Цитата Qraizer @ Т.е. таки сахар Я же сказал - надо подумать. Цитата Qraizer @ Не новая, улучшенная старая Т.е. вы таки покажете код, который гарантированно на любом компиляторе покажет мне требуемую диагностику? Цитата Qraizer @ Это прекрасно делалось мааааленькой модификацией семантики throw-спецификаторов. Т.е. не сахар. Цитата Qraizer @ Вот и я об этом. Коли исключение произошло, его требуется донести. Зачем к ему ещё одно новое? Только ради замены. Тогда зачем доносить исходное, если архитектурно оно должно быть заменено? В общем, я не вижу места этой фиче в продакшне. Но я оговорился, что тут могу ошибаться. Оставив в стороне необходимость фичи, я не понимаю, каким образом она является синтаксическим сахаром? Добавлено Цитата Qraizer @ После отработки делегируемого объект-то уже будет иметь свой собственный динамический тип, ведь так? С чего бы? Конструктор потомка то ещё не отработал. |
Сообщ.
#7403
,
|
|
|
Цитата MyNameIsIgor @ Зачем? Ты понял мою мысль, я понял твою. Я ж не говорю, мол, бесполезная фича, я говорю, без неё обойтись можно практически безболезненно. Для сравнения: без лямбд тоже обойтись можно, но отнюдь не так безболезненно.Ну, тогда измените мой пример. Цитата MyNameIsIgor @ Если б он был, не требовалось бы ничего нового стандартизировать. Фактически же, разница примерно как с неявным int-ом: в C это варнинг, в C++ - ошибка.Т.е. вы таки покажете код, который гарантированно на любом компиляторе покажет мне требуемую диагностику? P.S. Когда занимался мультиметодами, интеловый компилер достал просто этим варнингом. Но там так было нужно, это не ошибка. Получалось что-то вроде (после разворачивания списков типов): template <typename T> class Value { virtual T doIt() = 0; }; template <typename T1, typename T2> class A: public Value<T1>, public Value<T2> { /* ... */ }; template <typename T1, typename T2> class B1: public A<T1, T2> { virtual T1 doIt(); }; template <typename T1, typename T2> class B2: public B1<T1, T2> { virtual T2 doIt(); }; Добавлено Цитата MyNameIsIgor @ Ну не синтаксическим. Всё равно сахаром. Разве сложно это сделать самостоятельно? При определённых условиях. Я ради прикола когда-то реализовал подобную вещь на BC4.5 ещё, который в отличие от VC и Intel поддерживал спецификацию исключений для функций, и использовал её, чтобы протащить неожидаемое исключение сквозь спецификацию наружу. При условии единого полиморфного предка для всех классов исключений с фабрикой копирования контейнер сооружается легко. Вот только не пригодилось ни разу. Вся роль нового Стандарта тут, это обязывание компиляторов делиться скрытой RTTI с реализациями STL, чтобы те могли предоставить готовый же std::nested_exception без упомянутых ограничений. Оставив в стороне необходимость фичи, я не понимаю, каким образом она является синтаксическим сахаром? Добавлено Цитата MyNameIsIgor @ Но отработал конструктор конструируемого класса. И пусть делегируемый, а делегирующий ещё нет, деструктор-то вызовется, ежели чё.С чего бы? Конструктор потомка то ещё не отработал. Цитата MyNameIsIgor @ Не уловил сути задачи. Что мешает написать просто test(int& i) : i(i) {};? Замени на метод. Добавлено Чёрт... Парни, подскажите, где лучше всего создать тему по мультиметодам. В январе пойду в отпуск на пару недель, надо взять себя в руки и-таки опубликовать. Лучше всего подходят "Наши проекты", но я там редкий гость. Плюсовый раздел подходит для обсуждения, но не публикации. |
Сообщ.
#7404
,
|
|
|
Цитата Qraizer @ но я там редкий гость Ну и что, что редкий? Там и публикуй. |
Сообщ.
#7405
,
|
|
|
Та я ж забуду туда заглядывать.
Добавлено А! Подписка ж есть. Да, похоже ты прав. Добавлено О! А обсуждение можно и Плюсовом разделе оформить. Точно. |
Сообщ.
#7406
,
|
|
|
Дельфисты, поясните, плз, что тут не так:
type IMyInterface = interface ['некий GUID'] procedure Handle; end; IMyInterface2 = interface(IMyInterface) ['некий другой GUID'] end; TMyObject = class(TInterfacedObject, IMyInterface, IMyInterface2) // E2291: Missing implementation of interface method IMyInterface.Handle. protected procedure _Handle; procedure IMyInterface.Handle = _Handle; end; procedure TMyObject._Handle; begin end; class IMyInterface { public: virtual void Handle() = 0; }; class IMyInterface2: public IMyInterface { }; class TMyObject: virtual public IMyInterface, virtual public IMyInterface2 { protected: void _Handle() {} void Handle() { _Handle(); } }; TMyObject a; Добавлено P.S. Правильно ли я понимаю, что причина в разных GUID, из-за чего IMyInterface.Handle и IMyInterface2.Handle тоже разные, и если б GUID не различались (это вообще возможно?), то и проблемы б не было? |
Сообщ.
#7407
,
|
|
|
неверное имя в сообщении, похоже баг
Цитата Qraizer @ Дельфисты, поясните, плз, что тут не так: класс обязан выполнить два контракта: 1. автопилот(сопоставление по имени) TMyObject = class(TInterfacedObject, IMyInterface, IMyInterface2) protected procedure Handle; end; а) метод Handle в классе есть - контракт IMyInterface выполнен б) метод Handle в классе есть - контракт IMyInterface2 выполнен ок 2. ручное управление TMyObject = class(TInterfacedObject, IMyInterface, IMyInterface2) protected procedure _Handle; procedure IMyInterface.Handle = _Handle; end; а) контракт IMyInterface выполняется с помощью метода _Handle б) метод Handle отсутствует - - контракт IMyInterface2 НЕ выполнен фейл Цитата Qraizer @ Даже на Плюсах проверил: шикарно type IMyInterface = interface procedure Handle; end; IMyInterface2 = interface(IMyInterface) end; TMyObject = class(TInterfacedObject, IMyInterface, IMyInterface2) public procedure _Handle; procedure Handle; end; procedure TMyObject._Handle; begin end; procedure TMyObject.Handle; begin _Handle; end; тоже работает PS с т.з. языка IMyInterface, IMyInterface2 - это два разных типа это не зависит от наличия и значения GUID'а GUID можно указать любой, компилятор это не контролирует это конечно чревато, но иногда удобно type IMyInterface = interface ['GUID'] procedure Handle; safecall; end; IMyInterface2 = interface ['GUID'] function Handle:HRESULT; stdcall; end; TMyObject = class(TInterfacedObject, IMyInterface) public procedure Handle; end; ... Intf:=Obj as IMyInterface; // и далее работаем с исп. исключений Intf:=Obj as IMyInterface2; // исп. коды ошибок |
Сообщ.
#7408
,
|
|
|
Вот в этом-то и был вопрос: если IMyInterface2 расширяет IMyInterface, то IMyInterface.Handle в равной мере принадлежит обоим интерфейсам. Т.е. прикол в том, что ручная делегация не затрагивает IMyInterface2, и это не ошибка модели интерфейсов в языке, а тупо нефик лезть руками в вещи, которые легко сломать, если не понимаешь, что делаешь?
Добавлено Цитата Shaggy @ Ну это-то понятно. Другое дело, что один из них является подтипом другого и в этом смысле полностью заменяем им, но не наоборот (что, впрочем, при пустом IMyInterface2 не имеет значения). PS с т.з. языка IMyInterface, IMyInterface2 - это два разных типа это не зависит от наличия и значения GUID'а Добавлено Тогда дополнительно ещё три вопроса: Я не придираюсь, я хочу разобраться. На последний вопрос и в контексте Плюсов не так-то просто ответить. Добавлено Цитата Shaggy @ Хм... а это, случайно, не грязный хак? safecall кем обеспечивается? Разве не самим методом? это конечно чревато, но иногда удобно ... |
Сообщ.
#7409
,
|
|
|
от интерфейса не наследуются, его реализуют(как и получают) целиком, как неделимую единицу
поэтому в записи: TMyObject = class(TInterfacedObject, IMyInterface, IMyInterface2) IMyInterface реализуется один раз и доступен по одному маршруту в Interface table этого класса всего три записи: IInterface, IMyInterface, IMyInterface2 а из этого класса: TMyObject2 = class(TObject, IMyInterface2) мы не сможем получить даже IInterface т.к. в Interface table этого класса одна запись: IMyInterface2 но: var Obj:TMyObject2; Intf:IMyInterface2 I:IInterface; begin ... Intf:=Obj as IMyInterface2; // получение интерфейса // или Intf:=Obj; // неявный as .. I:=Obj; // неявный as, но облом, не реализован IInterface I:=Intf; // тут, т.к. IMyInterface наследуется от IInterface, просто усечение пример из жизни: в кафешке под пиво можно заказать набор закусок с соусами мне соусы не нужны, но: набор готовится с соусами и заказать можно только целиком (реализация и получение) но после получения заказа соус можно выкинуть (усечение) с сообщением похоже просто баг, я уже отправил репорт Цитата Qraizer @ а это, случайно, не грязный хак? ну как сказать... например, в самой IDE есть галочка - импортировать интерфейсы из TLB c safecall или stdcall методами Цитата Safecall functions automatically implement COM conventions for errors and exception handling, converting HRESULT error codes into exceptions. If you are entering function declarations in RIDL, you must explicitly specify the calling convention as safecall or stdcall. Добавлено и да, правильнее всё-таки говорить о расширении интерфейсов, а не о наследовании т.к. при такой записи (если бы она была разрешена) type IMyIntf3 = interface(IMyIntf, IMyIntf2) мы бы поимели ваши проблемы: дублирование _AddRef, _Release, QyeryInterface (и это только в самом простом случае) |
Сообщ.
#7410
,
|
|
|
Ну, как бы как я себе и представлял.
Цитата Shaggy @ Ага. Вот теперь у меня всё срослось. Вроде.с сообщением похоже просто баг, я уже отправил репорт Тогда в заключение: расширение интерфейса и его наследование в вашей терминологии – в чём разница? Я понимаю так, что расширение – это создание нового на основе существующего, при этом новый включает в себя из него всё. Наследование интерфейса как термин по-хорошему вообще не используется, и вместо него существует термин "реализация интерфейса". Получается, что нельзя создать новый интерфейс, расширив более одного? Добавлено Цитата Shaggy @ А, т.е. компилятор для safecall фактически создаёт некий прокси над тем, что написал програмер. О как. например, в самой IDE есть галочка - импортировать интерфейсы из TLB c safecall или stdcall методами Цитата Safecall functions automatically implement COM conventions for errors and exception handling, converting HRESULT error codes into exceptions. If you are entering function declarations in RIDL, you must explicitly specify the calling convention as safecall or stdcall. |