Страницы

Поиск по вопросам

среда, 27 ноября 2019 г.

Вынести метод шаблонного класса в .cpp

#c++ #шаблоны_с++ #c++_faq


Как вынести метод шаблонного класса из хэдера в cpp ?    


Ответы

Ответ 1



Необходимо помнить, что шаблон порождает код класса только тогда, когда вы употребляете этот шаблон в программе с конкретными параметрами. Это означает, что нельзя скомпилировать модуль содержащий просто шаблон класса. Шаблон — это еще не тип (в C#, напротив, угловые скобки говорят о типе Generic). Таким образом, реализация метода должна быть в том модуле, где этот метод используется, иначе получите Unresolved symbol. Вот пример, который скомпилировался в MSVS 2008: foo.h: #pragma once template class Foo { public: T bar(T a) const; }; main.cpp #include "foo.h" template T Foo::bar(T a) const { return a; } int main(int argc, char *argv[]) { Foo a; int b = a.bar(3); return 0; } Очевидно, в данном примере это равносильно варианту, когда реализация метода расположена в заголовочном файле. А вообще, если у Вас возникла такая задача, стоит задуматься, на верном ли Вы пути, так сказать :)

Ответ 2



Если Вам известно с какими типами будет инстанцироватся данный метод к шаблонном классе, то можно вынести эти специализации. Например, вот так: foo.h #pragma once template class Foo { public: T bar(T a) const; }; foo.cpp template<> int Foo::bar(int a) const { return a; } main.cpp #include "foo.h" int main(int argc, char *argv[]) { Foo a; int b = a.bar(3); return 0; } При этом, инстанцирование (точнее говоря вызов метода bar) с любым другим типом отличным от int будет приводить к ошибке.

Ответ 3



Вот очень элегантный метод, сам юзал: http://www.gamedev.ru/code/tip/?id=5303 // main.cpp #include "Templ.h" int main() { Templ templ(0); Templ templF(0.0f); Templ templD(0.0); return 0; } // Templ.h #pragma once template class Templ { public: Templ(T t); private: T x; }; // Templ.cpp #include "Templ.h" template Templ; template Templ; template Templ::Templ(T t) : x(t) { }

Существует ли ФГИС ЕГРН API?

#поиск_api #росреестр


Существует ли API-сервис для получения данных из ФГИС ЕГРН или какой-либо иной способ
получения выписок ЕГРН из Росреестра?
    


Ответы

Ответ 1



Описание веб-сервисов: http://pkk5.rosreestr.ru/help/pkk5_services.docx Веб-сервисы: http://pkk5.rosreestr.ru/arcgis/rest/services Открытые данные: https://rosreestr.ru/wps/portal/cc_ib_opendata Описание «сервиса Росреестра прямого доступа»: http://rosreestr.ru/wps/portal/cc_ib_documents?documentId=1521 Веб-сервис прямого взаимодействия обеспечивает полный цикл оказания государственных услуг Росреестра в электронном виде (от подачи запроса и информирования заявителя о ходе исполнения услуги до предоставления результата оказания услуги в виде электронного документа). Предоставление сведений государственного кадастра недвижимости о земельном участке в виде кадастрового паспорта объекта недвижимости; Предоставление сведений государственного кадастра недвижимости о земельном участке в виде кадастровой выписки; Предоставление сведений государственного кадастра недвижимости о территории в пределах кадастрового квартала в виде кадастрового плана территории; Постановка на государственный кадастровый учет земельного участка; Постановка на государственный кадастровый учет объекта капитального строительства. Предоставление выписки из ЕГРП о правах отдельного лица; Предоставление выписки из ЕГРП о зарегистрированных правах на объект недвижимого имущества (земельные участки и объекты капитального строительства). Ещё есть описание REST-ресурсов сервиса «Онлайн-Справка» версии 0.0.2 Макро-регионы http://rosreestr.ru/api/online/macro_regions Типы дочерних регионов http://rosreestr.ru/api/online/region_types/{parent-id} Пример: http://rosreestr.ru/api/online/region_types/104201000000 Дочерние регионы по идентификатору родителя http://rosreestr.ru/api/online/regions/{parent-id} Пример: http://rosreestr.ru/api/online/regions/104201000000 Поиск объекта по идентификатору http://rosreestr.ru/api/online/fir_object/{object-id} Пример: http://rosreestr.ru/api/online/fir_object/2:56:30302:639 Поиск объектов по номеру http://rosreestr.ru/api/online/fir_objects/{number} Пример: http://rosreestr.ru/api/online/fir_objects/2:56:30302:639 Результат: 0 или множество (не больше 200) объектов, удовлетворяющих маске номера. Поиск объекта по коду региона и номеру права или ограничения http://rosreestr.ru/api/right/{region}/{number} Пример: http://rosreestr.ru/api/online/right/177/50-50-21%2F042%2F2012-234 Результат: 0 или 1 объект, номер права или ограничения которого совпал с указанным номером. Поиск объектов методом GET http://rosreestr.ru/api/online/address/fir_objects?macroRegionId=140000000000&RegionId=140281000000&street=Полевая&house=1 Передаваемые поля. Числа в виде строк: macroRegionId — id макрорегиона regionId — id региона settlementId — id населенного пункта Передаваемые поля. Строки: settlementType — тип населенного пункта (необязательное поле, фильтрует населенные пункты от типа) street — наименование улицы house — номер дома apartment — номер квартиры building — номер корпуса structure — номер строения streetType — тип улицы (необятельное поле) Возможные значения streetType: str1=Улица str2=Переулок str3=Проспект str4=Площадь str5=Микрорайон str6=Аллея str7=Бульвар str8=Аал str9=Аул str10=Въезд str11=Выселки str12=Городок str13=Деревня str14=Дорога str15=ж/д остановочный (обгонный) пункт str16=Железнодорожная будка str17=Железнодорожная казарма str18=Железнодорожная платформа str19=Железнодорожная станция str20=Железнодорожный пост str21=Железнодорожный разъезд str22=Животноводческая точка str23=Заезд str24=Казарма str25=Квартал str26=Километр str27=Кольцо str28=Линия str29=Местечко str30=Набережная str31=Населенный пункт str32=Остров str33=Парк str34=Переезд str35=Планировочный район str36=Платформа str37=Площадка str38=Полустанок str39=Поселок/станция str40=Поселок сельского типа str41=Починок str42=Почтовое отделение str43=Проезд str44=Просек str45=Проселок str46=Проулок str47=Разъезд str48=Сад str49=Село str50=Сквер str51=Слобода str52=Станция str53=Строение str54=Территория str55=Тракт str56=Тупик str57=Участок str58=Хутор str59=Шоссе

Ответ 2



Если я не ошибаюсь, то вот API версия 3.0 Beta для работы с Росреестром в режиме on-line Авторизация и методы написаны, соответственно, на этой странице

Ответ 3



Поиск объектов по адресу - не методом POST, а методом GET. В документации автором допущена ошибка. Рабочий пример запроса к API: http://rosreestr.ru/api/online/address/fir_objects?macroRegionId=140000000000&RegionId=140281000000&street=Полевая&house=1 Кому, вдруг, пригодится: https://github.com/KirillNaumkin/RosreestrREST - NET-либа для встраивания в свои приложения функционала запроса к сервисам РР и мини-приложение для тестирования либы. Там же подробно расписана структура ответов сервиса.

Ответ 4



Сервис Каднет предоставляет API v2 для отправки запросов в Росреестр ФГИС ЕГРН https://api.kadnet.ru/ Документация методов https://documenter.getpostman.com/view/2625849/kadnet-api/6tgTfhm#intro .Net Client https://github.com/kadnet/kadnet.apiv2.dotnet

Передача по значению в Java

#java


Добрый день. Читал про вызов по значению и натолкнулся на два примера. 1-ый:

public class Application {
    public static void main(String[] args) {
        String[] x = {"A"};
        String[] y = x;
        x[0] = "B";
        System.out.print(x[0] + " " + y[0]);
    }
}


Тут вроде бы все понятно. Ссылка на строковый массив "y" будет совпадать со ссылкой
на массив "x"и произойдет копирование и ответом будет "B B". Но вот второй пример:

public class Application {
    public static void main(String[] args) {
        String x = "A";
        String y = x;
        x = "B";
        System.out.print(x + " " + y);
    }
}


Здесь почему то ответ "B A", хотя я думал что правильный ответ будет "B B". Ход рассуждений
был такой же как и в первом примере. Подскажите пожалуйста, что за подвох в этом примере
? Ведь String - это класс, а не тип в Java и в обоих примерах мы создаем экземпляр
класса String.
    


Ответы

Ответ 1



В первом случае у вас есть массив (обозначим его M, хотя в Java вы не можете обратиться к нему иначе, как через ссылку). Нулевой элемент массива M указывает сначала на строку "A", затем на строку "B". И x, и y, заметьте, ссылаются на один и тот же массив M. Когда вы меняете данные в массиве через любую из ссылок, вы меняете одни и те же данные. Во втором случае у нас есть переменные x и y, которые ссылаются сначала на одну и ту же строку "A", а затем x начинает ссылаться на другую строку ("B"). Всё просто. Вот вам аналогия. В первом случае у вас есть клетка. И вы, и я смотрим на эту клетку. В клетке сначала сидел белый кролик, а потом туда посадили чёрного кролика. Теперь и вы, и я смотрим на клетку с чёрным кроликом. Во втором случае клетки нет, я смотрю на белого кролика, вы смотрите на того же кролика, что и я, а потом я отвернулся и стал смотреть на чёрного кролика. Ну да, теперь мы смотрим на разных кроликов. Теперь замените кроликов на строки, клетку на массив, «смотреть» на «иметь ссылку». Вы не должны искать универсальных простых правил типа «если я меняю вот эту штуку, та тоже поменяется». Или «не поменяется». Или «поменяется, если уровень косвенности больше 1». Рассуждайте о смысле операций каждый раз. Не удержался, добавил картинки, о которых говорил @void. Смотрите. Первый пример: String[] x = {"A"}; String[] y = x; x[0] = "B"; Второй пример: String x = "A"; String y = x; x = "B"; Так понятнее?

Ответ 2



В первом случае у вас есть 2 ссылки на один и тот же массив. String[] x = {"A"}; //x указывает на массив {"A"} (x[0] == "A") String[] y = x; //x и y указывают на массив {"A"} (x == y; x[0] == y[0]; x[0] == "A"; y[0] == "A") x[0] = "B"; //в массиве {"A"} строка с индекcом 0 поменялась на строку "B", изменилось состояние массива и теперь это массив {"B"}. Но это все еще тот же самый объект (x == y; x[0] == y[0]; x[0] == "B"; y[0] == "B") Во втором же случае у вас две разных ссылки на экземпляры класса String: String x = "A"; //x указывает на строку "A" String y = x; //x и y указывают на строку "A" (x == y) String x = "B" //x указывает на строку "B", y указывает на строку "A" (x != y)

Ответ 3



Никак невозможно изменить содержимое созданной строки, по крайней мере в безопасном (safe) коде и без рефлексии. Поэтому вы при изменении строк изменяете не сами строки, а значения переменных, указывающих на строки. Например, код s = s.Replace ("foo", "bar"); не изменяет содержимое строки s, которое было до вызова метода Replace — он просто переназначает переменную s на новообразованную строку, которая является копией старой за исключением всех подстрок «foo», заменённых на «bar».

Что означает @ после имени функции в C++?

#c++ #windows


Например, функция WinMain@16. Что означает "собака" и число после нее? У меня есть
идея, что это общий размер параметров в байтах, но я не уверен в этом.
    


Ответы

Ответ 1



В си перегружать функции нельзя, поэтому, когда код компилируется, компилятор может использовать имена функций по назначению. В с++ можно перегружать функции, а в скомпилированном коде уже нет данных о аргументах. Поэтому, компилятор делает "манглирование". В данном случае просто кодирует размер аргументов и добавляет их таким образом. Это позволяет потом линковщику все собрать правильно в исполнимый файл. Чуточку больше.

Ответ 2



Это вовсе не имя функции. Это компиляторозависимый name mangling — имя дополняется другой информацией для внутренних целей. Смысла вне конкретного компилятора и его конкретной версии не имеет. Реальное имя функции — WinMain. Если вы пытаетесь скомпилировать под Windows что-нибудь нестандартным компилятором, возможно, вам нужно почитать этот ответ. Поскольку известно, что WinMain использует конвенцию вызова __stdcall, то согласно официальной документации правильное имя должно быть _WinMain@16 (спасибо @Abyx за уточнение).

Запрос на соединение двух таблиц в MySQL

#mysql #sql


Помогите, пожалуйста, просто составить запрос-образец.

Есть первая таблица, в которой есть столбцы спортсмен и серийный_номер_велосипеда.
Вторая таблица: серийный_номер_велосипеда, цвет, год_выпуска.

Какой будет единый запрос, чтобы выбрать спортсмен, серийный_номер_велосипеда, цвет,
год_выпуска?
    


Ответы

Ответ 1



Используйте соединение таблиц: Если список серийных номеров велосипеда в обеих таблиц совпадает (нет таких элементов, которые есть в одной таблице, но нет во второй), то можете использовать внутреннее соединение join (inner join): SELECT s.sportsman, s.serial, b.color, b.year FROM sportsmen s JOIN bike b ON s.serial = b.serial Пример таблицы на sqlfiddle Результат выполнения запроса Либо: SELECT s.sportsman, s.serial, b.color, b.year FROM sportsmen s, bike b WHERE s.serial = b.serial Результат выполнения запроса Если список серийных номеров велосипедов не совпадает, то при соединении таблиц с помощью внутреннего соединения inner join (join) можно потерять нужные строки, поэтому для сохранения всех строк в левой таблице надо использовать left join: SELECT s.sportsman, s.serial, b.color, b.year FROM sportsmen s LEFT JOIN bike b ON s.serial = b.serial Пример таблицы на sqlfiddle Результат выполнения запроса

Ответ 2



SELECT с.спортсмен, в.серийный_номер_велосипеда, в.цвет, в.год_выпуска FROM спортсмен с LEFT JOIN велосипед в ON с.серийный_номер_велосипеда = в.серийный_номер_велосипеда;

Ответ 3



Вам нужна инструкция left join select t1.*, t2.color, t2.year from t1 left join t2 on t1.serial_num = t2.serial_num

Расположение рисованных кругов CSS

#css #сss3


Есть стиль, выглядит так: 



Нужно сделать, чтобы круги располагались в шахматном порядке, как на картинке ниже. 



Нужно замостить так весь бэкграунд.

body {
  background: radial-gradient(circle, #ff72f7 40%, rgba(255,114,247,0) 40%) 100px 100px;
  background-color:white;
  background-size:250px 250px;
}

    


Ответы

Ответ 1



.polkaDot { background: radial-gradient(circle, #ff72f7 30%, rgba(255,114,247,0) 30%), radial-gradient(circle, #ff72f7 30%, rgba(255,114,247,0) 30%) 125px 125px; background-color:white; background-size: 250px 250px; }

Зачем нужен static class?

#java #дизайн_языка


Статические переменные нужны для доступа к ним, без создания экземпляра класса. А
вот зачем нужен static класс?
    


Ответы

Ответ 1



Статическим классом в java может быть только вложенный класс. Если класс отмечен как static, то он ведет себя, как обычный класс. например, есть класс А, вложенный статический класс B и вложенный (нестатический) класс С: public class A{ ... static public class B{ } public class C{ } } и мы хотим создать экземпляры этих классов во "внешнем" коде public class Test{ public static void main(String[] args) { A a = new A(); // обычный класс A.B b = new A.B(); // статический вложенный класс A.C c = a.new C(); // вложенный класс, связан с экземпляром А // A.C c = new A.C(); // синтаксическая ошибка (не скомпилится) } } или внутри статических методов класса А public class A{ ... static public class B{ } public class C{ } public static void main(String[] args) { A a = new A(); // обычный класс A.B b = new A.B(); // статический вложенный класс A.C c = a.new C(); // вложенный класс, связан с экземпляром А // A.C c = new A.C(); // синтаксическая ошибка (не скомпилится) } public static void test() { A a = new A(); // обычный класс A.B b = new A.B(); // статический вложенный класс A.C c = a.new C(); // вложенный класс, связан с экземпляром А // A.C c = new A.C(); // синтаксическая ошибка (не скомпилится) } } На мой взгляд использование статического класса может быть уместно, как небольшой класс, который по смыслу тесно связан с "основным" внешним классом. Например: public class Tree{ static public class Node{ } } В этой ситуации так же можно вынести вложенный класс в обычный и переместить оба класса в отдельный package. Единственным отличием вложенного статического класса от обычного, которое мне видится, - это более снисходительное отношение к видимости методов и полей между вложенным классом и его внешним классом. Например: public class A { private void privateMethod(){ B b = new B(); b.privateMethod(); // есть доступ к приватным методам/полям } static public class B { private void privateMethod(){ A a = new A(); a.privateMethod(); // есть доступ к приватным методам/полям } } } Ссылка на документацию: https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

Ответ 2



В основном для того, чтобы можно было создавать вложенные классы, объекты которых можно создавать, не создавая инстанса класса в котором он лежит.

Ответ 3



"Статическим классом в java может быть только вложенный класс" - есть вложенные(static) и внутрение, разница как и в обычном плане, static имеет доступ только к статичным полям

Где хранить документацию и вспомогательные файлы проекта?

#git #github #документация


Где хранить документацию и вспомогательные файлы, которые не относятся к коду, например,
скриншоты для README.md?

По скриншотам нашел два ответа на enSO:


How to add screenshot to READMEs in github repository ?
Add images to README.md on GitHub


Но там больше затрагивается проблема оформления README.md через Markdown. Меня же
интересуют лучшие практики для хранения вспомогательных данных. Какое место выбрать
для хранения? Отдельная ветка или репозиторий? Как использовать эти вспомогательные данные?

Пока вижу для себя следующее решение. Создаю в проекте ветку с вспомогательными данными
и кладу туда скриншоты, а к ним уже обращаюсь из файла README.md.

Для документации ситуация аналогична; думаю, пока проект небольшой, доки могут храниться
в одном репозитории.

Сам сейчас использую GitLab/GitHub.

Поделитесь, пожалуйста, своим опытом.
    


Ответы

Ответ 1



Наверное самое лучшее решение иметь confluence, а так же хранить проект либо на bitbuckete(jira), либо tfs, если windows разработка, там очень мощные возможности вести документацию и хранить вспомогательные файлы

Ответ 2



Хранить документацию (скриншоты и диаграммы относятся к ней) лучше в той же ветке, что и код. Например, в отдельно директории в корне проекта диретория docs. Чем "ближе" документация к коду, тем меньше вероятность расхождения кода и документации. Для многих фреймворков и систем сборки существуют правила хранение документации к коду. Например, maven ожидает, что у вас будет директория site и в ней будет документация и тогда maven сможет её отформатировать и загрузить на сайт. Так же многие фреймворки могут выдавать ошибки, если к коду отсутствует документация. Существуют различные плагины к системам сборки которые помогают создавать, проверять и публиковать документацию. Например, AsciiDoctor имеет плагины для различных систем сборки.

Ответ 3



Если документация - это отдельный проект, который разрабатывается отдельными людьми и никак реально не связан с кодом -- то стоит завести отдельный репозиторий. Так например делает github, создавая под wiki вполне самостоятельный репозиторий, которым можно отдельно управлять и вести историю изменений.

Ответ 4



1. Мнение Подход, который мне больше всего нравится — создание для документации отдельного сайта. Так делают разработчики Open Source проектов, которые мне представляются наиболее серьёзными и значимыми. Это можно осуществить бесплатно, если пользоваться генераторами статических сайтов. 2. Примеры документаций, сделанных при помощи средств, помогающих размещать их на отдельных сайтах MkDocs — пример ReadTheDocs — пример Sphinx — некоторые проекты, использующие Sphinx; пример: 3. Аргументы Основной аргумент — ограничения хостингов для размещения HTML-сайтов ниже тех, с которыми приходится иметь дело при размещении документации на BitBucket, GitHub (но не с BitBucket Pages, GitHub Pages), GitLab и аналогичных ресурсах. Положим, если Вы решили разместить документацию в README.MD и прочих .md файлах на GitHub: 3.1 Доступно Всё, что позволено разметкой Markdown, но не то что в Markdown достигается средствами HTML, а не самого Markdown. Упрощённо говоря, Вы можете использовать чёрный по белому текст, изображения, таблицы, но не более того. 3.2 Недоступно Не получится использовать JavaScript: Вы не сможете использовать JQuery-плагины, сделать удобное меню на Bootstrap для удобства перемещения пользователей по Вашей документации, вынуждены будете отказывать себе в мелочах вроде кастомного скроллбара и т. д. Не получится встроить видео без перехода на другую страницу для его просмотра. 4. Особенности генераторов статических сайтов Писать сайты прямо в HTML не очень удобно. К счастью, одной из функций генераторов статических сайтов является рендеринг текста, написанного в удобной для Вас разметке, как то Markdown или reStructuredText, непосредственно в HTML. Возможность интеграции с инструментами для сборки: я, допустим, использую Pelican + Grunt + CoffeeScript + Stylus. Существуют генераторы, специально ориентированные для написания документаций к проектам. Некоторые примеры приведены в разделе 2. Притом если Вас устраивают уже имеющиеся темы, можно использовать их, а не писать с нуля. 5. Дополнительные ссылки Static Site Generators — бесплатная книга издательства O'Reilly, Working with Static sites, Альтернативы MkDocs на AlternativeTo.Net.

Как и какими средствами находить ошибки в PHP коде?

#php #отладка #обработка_ошибок #php_faq


При разработке, порой, код не работает так, как задумано или вообще не работает.
Сижу, гадаю: что и где не так?

Час посмотрев на код - иду на проф. ресурсы, например Stack Overflow и публикую вопрос
 "Где здесь ошибка?" или "Почему не работает?"

В итоге часто проблема мелкая, дурацкая опечатка, ошибка в синтаксисе и прочее. Профессионалом
так не станешь, если по каждой ерунде бегать по ресурсам. А я хочу им быть.

Вопрос: какие есть способы, чтобы найти ошибки в PHP коде? Какие инструменты, методы,
плагины, пути и пр.? 
    


Ответы

Ответ 1



Вчера всё работало, а сегодня не работает / Код не работает как задумано или Debugging (Отладка) В чем заключается процесс отладки? Что это такое? Процесс отладки состоит в том, что мы останавливаем выполнения скрипта в любом месте, смотрим, что находится в переменных, в функциях, анализируем и переходим в другие места; ищем те места, где поведение отклоняется от правильного. Будет рассмотрен пример с PHPStorm, но отладить код можно и в любой другой IDE. Подготовка Для начала необходимо, чтобы в PHP имелась библиотека для отладки под названием xdebug. Если её еще нет, то надо скачать на xdebug.org. Обычно все библиотеки лежат в папке ext внутри папки PHP. Туда и надо поместить dll. Далее в php.ini прописываем настройки: [Xdebug] zend_extension="C:/server/php/ext/php_xdebug.dll" //
Пример с анимацией молнии: .lightning { position: relative; height: 200px; width: 200px; border-radius: 50%; margin: 50px auto; } .lightning:after, .lightning:before { position: absolute; content: ''; height: 100%; width: 100%; top: 0%; left: 0%; } .lightning:after { background: white; border: 2px solid; border-radius: 50%; z-index: -1; } .lightning:before { background: linear-gradient(transparent 0%, yellow 0%), linear-gradient(to top left, yellow 43%, gray 43%, gray 44%, transparent 44%), linear-gradient(to top left, transparent 56%, gray 56%, gray 57%, yellow 57%), linear-gradient(transparent 0%, gray 0%), linear-gradient(to top left, gray 51%, transparent 51%), linear-gradient(to top left, transparent 49%, gray 49%); background-size: 20% 40%, 22% 42%, 22% 42%, 23% 42%, 23% 42%, 23% 42%; background-position: 50% 50%, 32% 5%, 70% 100%, 50% 50%, 33% 7%, 69% 98%; background-repeat: no-repeat; backface-visibility: hidden; transform: skewY(-30deg) skewX(-30deg); z-index: 2; } /* Just for demo */ body { background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%); } .lightning { transition: all 1s; } .lightning:hover:before { animation: boltstrike 1s; } @-webkit-keyframes boltstrike { 25% { transform: translateX(-5%) translateY(5%) skewY(-30deg) skewX(-30deg); } 50% { transform: translateX(7.5%) translateY(-7.5%) skewY(-30deg) skewX(-30deg); } 100% { transform: skewY(-30deg) skewX(-30deg); } } @keyframes boltstrike { 25% { transform: translateX(-5%) translateY(5%) skewY(-30deg) skewX(-30deg); } 50% { transform: translateX(5%) translateY(-5%) skewY(-30deg) skewX(-30deg); } 100% { transform: skewY(-30deg) skewX(-30deg); } }
Ссылка на демо в полный экран с анимацией и изменением цвета. Перевод ответа: Create a lightning bolt design (like The Flash) @Harry

Статическое поле в generics/template

#java #c_sharp #c++ #generics


Есть Java generics класс типа:

public class MyClass {
   static long myField=System.currentTimeMillis();

   //blah-blah
}


Создаются два объекта:

MyClass var1=new MyClass();
MyClass var2=new MyClass();


вопрос: одинаковы ли var1.myField и var2.myField?

Update

А если это будет шаблон в С++/C# - тогда будут они одинаковы или нет?
    


Ответы

Ответ 1



У Java с type erasure MyClass и MyClass — это по сути в рантайме один и тот же класс. У C# нет type erasure, поэтому MyClass и MyClass — разные классы. Отсюда следует и различие в статических полях: если класс один и тот же, статическое поле общее. У C++ template — это вообще текстовая подстановка по сути, каждый шаблон класса инстанциируется в отдельный класс, соответственно и статические переменные там разделены.

Ответ 2



Ответ: Да, они одинаковые для Java Ваш пример не самый хороший для демонстрации этого. Известно, что StringBuilder не ссылается в один pool и каждый раз создаёт новый объект. Будем использовать его для подтверждения утверждения: public class Clazz { static StringBuilder myField= new StringBuilder("Test text"); public static void main (String args[]) throws InterruptedException { Clazz var1=new Clazz(); Clazz var2=new Clazz(); // Одинаковые ли ссылки на объект? System.out.println(var1.myField == var2.myField); // Одинаковы ли содержания объектов? System.out.println(var1.myField.toString().equals(var2.myField.toString())); } } Output: true true В C++, на сколько я понял, нет прямого аналога generic class. Там есть шаблоны и работают они как-то по-другому. Я набросал немного кода: template class Test { public: static int count; }; template int Test ::count; int main() { Test a; Test b; Test c; a.count = 2; b.count = 1; c.count = 1; // Одинаковы ли ссылки? cout << (&a.count == &b.count) << endl; // Одинаковы ли содержания? cout << (a.count == b.count)<< endl; // Одинаковы ли ссылки? cout << (&a.count == &c.count) << endl; // Одинаковы ли содержания? cout << (a.count == c.count) << endl; return 0; } Статическая переменная внутри шаблона оказывается одинаковой для объектов, созданных одинаковым типом (int) и разная для разных типов. Вывод этой программы следующий: Output: 1 1 0 1 В C# провести исследование нет возможности (ОС не поддерживает), но я нашёл похожий вопрос на англоязычном StackOverflow: Are static members of a generic class tied to the specific instance?. Дела там, похоже, не особо отличаются от C++. Статическая переменная одинакова для всех экземпляров одинакового типа. Foo и Foo - два разных типа. Это можно показать в следующем примере: // Результатом будет "False" Console.WriteLine(typeof(Foo) == typeof(Foo)); Это можно найти в 1.6.5 параграфе спецификации языка C# (for C# 3): ....

Ответ 3



C#: нет, они разные class Generic { static object obj = new object(); public object GetObject() { return obj; } } static void Main() { var g1 = new Generic(); var g2 = new Generic(); Console.WriteLine( (g1.GetObject() == g2.GetObject() ? string.Empty : "Not ") + "Same"); } Output: Not Same

Ответ 4



Для C++ разные, т.к. разные типы аргумента для шаблона порождают разные классы, никак не связанные друг с другом. #include template struct MyClass { static long myField; }; int main() { auto var1 = MyClass(); auto var2 = MyClass(); std::cout << std::boolalpha << (&var1.myField == &var2.myField) << std::endl; } Вывод: false

Достоинства и недостатки использования async/await при работе с событиями

#c_sharp #.net


В этой теме прозвучала фраза, что работа с событиями по модели async/await имеет
множество плюсов нежели традиционный событийных подход-подписался и забыл.


  Теоретически, можно жить и без async/await. Но тогда у вас будет код
  разбросан по обработчикам событий, и состояние будет в виде глобальных
  переменных. А об обработке исключений я уже и не говорю — с ней будет
  совсем тяжко. Но да, как-то люди ж без async/await жили раньше, и в
  других языках до сих пор живут.


Собственно, меня это заинтересовало.

Хотелось бы получить информацию о всех достоинствах и возможно недостатках с примерами,
традиционного подхода и подхода через async/await.
    


Ответы

Ответ 1



Смотрите. Традиционый метод асинхронной работы — использование callback'ов. В каждой точке, где у вас await при этом вы должны завершить работу метода, подписавшись на продолжение окончание асинхронного кода. При этом вы должны где-то сохранить ваше состояние, то есть вы должны при этом таскать с собой локальные переменные вручную. Далее, логика циклов и условий тоже получается размазанной по нескольким кускам кода. Ну и делить на нужные части вам придётся вручную. Вот пример простого async-кода: копирование потоков. async Task CopyAsync(Stream source, Stream target, CancellationToken ct) { try { var buf = new byte[8192]; while (true) { var actuallyRead = await source.ReadAsync(buf, 0, buf.Length, ct); if (actuallyRead == 0) return; await target.WriteAsync(buf, 0, actuallyRead, ct); } } catch (OperationCanceledException) when (ct.IsCancellationRequested) { Debug.WriteLine("Cancelled"); } } Ничего особенного нет. Как нам написать ту же функциональность без синхронного кода, не занимая поток? У нас есть метод stream.BeginRead, который должен вернуть объект типа IAsyncResult. Попробуем смоделировать нашу функциональность таким же образом. Для начала, нам нужно где-то хранить буфер, а также рабочие потоки. Для этого нам понадобится класс. Назовём его StreamCopyWorker, имея в виду, что логика работы будет тоже внутри него. Затем, мы хотим определить IAsyncResult. Объявим его отдельным классом, так как это всё же отдельная сущность. В StreamCopyWorker должны быть методы BeginCopyAsync и EndCopyAsync. Имплементируем. Получается вот такой крокодил: internal class StreamCopyWorker { internal readonly IAsyncResult Result; Stream source; Stream target; CancellationToken ct; ManualResetEventSlim ev = new ManualResetEventSlim(); AsyncCallback cb; public StreamCopyWorker( Stream source, Stream target, object state, CancellationToken ct, AsyncCallback cb) { this.source = source; this.target = target; this.ct = ct; this.cb = cb; this.Result = new StreamCopyAsyncResult() { AsyncState = state, AsyncWaitHandle = ev.WaitHandle, self = this }; } byte[] buf = new byte[8192]; internal void BeginAsync() { source.BeginRead(buf, 0, buf.Length, DoWrite, null); } internal void EndAsync(IAsyncResult ar) { ct.ThrowIfCancellationRequested(); } void DoWrite(IAsyncResult ar) { int bytesRead = source.EndRead(ar); if (bytesRead == 0 || ct.IsCancellationRequested) Finish(); else target.BeginWrite(buf, 0, bytesRead, DoRead, null); } void DoRead(IAsyncResult ar) { target.EndWrite(ar); if (ct.IsCancellationRequested) Finish(); else BeginAsync(); } void Finish() { ((StreamCopyAsyncResult)Result).IsCompleted = true; ev.Set(); cb(Result); } internal class StreamCopyAsyncResult : IAsyncResult { public bool IsCompleted { get; internal set; } public WaitHandle AsyncWaitHandle { get; internal set; } public object AsyncState { get; internal set; } public bool CompletedSynchronously => false; internal StreamCopyWorker self { get; set; } } } Ну и вспомогательные методы для вызова, чтобы спрятать создание класса: IAsyncResult BeginCopyAsync(Stream source, Stream target, object state, CancellationToken ct, AsyncCallback cb) { var worker = new StreamCopyWorker(source, target, state, ct); worker.BeginAsync(); return worker.Result; } void EndCopyAsync(IAsyncResult ar) { var result = (StreamCopyWorker.StreamCopyAsyncResult)ar; var worker = result.self; worker.EndAsync(ar); } Вам всё ещё кажется, что без async/await легко? С чистой событийной моделью получается спагетти ещё похлеще. Сейчас можно протягивать состояние через замыкания, и это немного упрощает код. Но не слишком. У меня та же задача на чистых событиях выглядит примерно так: var buf = new byte[8192]; ResultCallback cb = (o, args) => { if (args.IsCancelled) Debug.WriteLine("Cancelled"); }; ReadHandler rhandler = null; rhandler = (o, args) => { source.ReadFinished -= rhandler; if (ct.IsCancelationRequested) cb?.Invoke(null, new ResultArgs(isCancelled: true)); else { var readBytes = args.ReadBytes; if (readBytes == 0) cb?.Invoke(null, new ResultArgs(isCancelled: false)); else { WriteHandler whandler = null; whandler = (o, args) => { target.WriteFinished -= whandler; if (ct.IsCancelationRequested) cb?.Invoke(null, new ResultArgs(isCancelled: true)); else { source.ReadFinished += rhandler; source.ReadAsync(buf, 0, buf.Length); } }; target.WriteFinished += whandler; target.WriteAsync(buf, 0, readBytes); } } }; source.ReadFinished += rhandler; source.ReadAsync(buf, 0, buf.Length); (плюс определение ResultCallback, ReadHandler, WriteHandler, ResultArgs и т. д.). Наверняка вы видели похожие, только более крупные «пирамиды смерти» в коде на Javascript. Вы понимаете, что в этом коде творится? Я уже нет.

Ответ 2



Допустим, у нас есть задача для UI приложения: выполнить какую то логику, потом показать представление, дождаться, когда это представление будет закрыто и выполнить ещё что то. Как это решалось бы традиционным способом (я использую Window в качестве представления чисто для упрощения примера, в реальной задаче вместо окна может быть что угодно): int i = 0; void EventBased() { i = DoSmthg(); var wnd = new Wnd(); wnd.Closed+=Closed; wnd.Show(); } void Closed(object sender, EventArgs e) { (sender as Wnd).Closed -= Closed; DoSmthgElse(i); } Обратите внимание на 3 вещи: Логика казалось бы одного метода раскидана по нескольким методам. Это, конечно, можно исправить, назначив обработчик прямо на месте анонимным делегатом, но и там есть свои минусы. EventBased() метод неблокирующий. То есть тот, кто будет вызывать этот метод, не узнает об окончании работы всей логики. Это тоже решается добавлением фрейма в диспетчер или через wnd.ShowDialog() если wnd - окно (хотя это по сути также добавление фрейма), или новым событием, что тоже имеет свои минусы. Мы вынуждены хранить в поле i значение промежуточного результата. Это тоже можно было бы обойти анонимным делегатои, но это привело бы все равно к захвату переменной Как видите, желая решить казалось бы простую задачу, приходится изворачиваться, чтобы заставить код работать так, как требуется. Но давайте напишем такое окно, с которым работать будет проще: public class Wnd : Window { TaskCompletionSource s; public Wnd() { s = new TaskCompletionSource(); this.Closed+= (sender, args) => s.SetResult(this); } public Task ShowAsync() { this.Show(); return s.Task; } } Как видно, у окна теперь есть метод, который вернет таск. И этот таск завершится только когда окно будет закрыто. Теперь мы можем переписать вызывающий код следующим образом: async Task AsyncBased() { var i = DoSmthg(); var wnd = new Wnd(); await wnd.ShowAsync(); DoSmthgElse(i); } Больше нет необходимости шаманить с фреймами или делегатами или ещё с чем-либо. Вся нужная логика сосредоточена в одном методе (мы то знаем, что это не совсем так, но для читателя кода это верно), также вызывающий код может дождаться конца работы логики не прибегая к черной магии Промежуточное состояние выглядит как обычная локальная переменная Это просто один из простых примеров, что можно жить и без async/await, но использование async/await делает код немного лаконичней и понятней. Вы можете заменить окно чем угодно (получением данных из сети, записью в БД, любым асинхронным вызовом), окно взято чисто для примера работы с TaskCompletionSource.