Страницы

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

пятница, 11 января 2019 г.

Функция, принимающая указатель на другую функцию

Функция принимает в аргумент указатель на другую функцию. Как правильно объявить прототип?


Ответ

С++: посредством typedef
Неформально:
typedef ReturnType(*FunctionPtr)(Parm1Type, Parm2Type, ...);
Прототип:
typedef void(*FunctionPtr)(); void func(const FunctionPtr& functionPtr);
Пример кода:
void parmFunc(){}
typedef void(*FunctionPtr)(); void func(const FunctionPtr& functionPtr){ functionPtr(); }
int main() { func(&parmFunc); }

С++11: посредством using
Неформально:
using FunctionPtr = ReturnType(*)(Parm1Type, Parm2Type, ...);
Прототип:
using FunctionPtr = void(*)(); void func(const FunctionPtr& functionPtr);
Пример кода:
void parmFunc(){}
using FunctionPtr = void(*)(); void func(const FunctionPtr& functionPtr){ functionPtr(); }
int main() { func(&parmFunc); // вариант 1 func([](){/* code of your function */}); // вариант 2 }

C++11: посредством std::function
Неформально:
using FunctionPtr = std::function;
Прототип:
#include
using FunctionPtr = std::function; void func(const FunctionPtr& functionPtr);
Пример кода:
#include
void parmFunc(){}
using FunctionPtr = std::function; void func(const FunctionPtr& functionPtr){ functionPtr(); }
int main() { func(&parmFunc); // вариант 1 func(std::bind(parmFunc)); // вариант 2 func([](){/* code of your function */}); // вариант 3 }

Если ваша функция должна возвращать значение и/или принимать параметры, то смотрите неформальное описание в данном ответе.

Какой формат у nginx.conf?

Работаю с файлами конфигурации nginx. Они имеют формат, который мне ранее не встречался: что-то похожее на смесь .ini и JSON:
user www www; ## Default: nobody worker_processes 5; ## Default: 1 error_log logs/error.log; pid logs/nginx.pid; worker_rlimit_nofile 8192;
events { worker_connections 4096; ## Default: 1024 }
Хочу привязать к этим файлам какой-то конкретный формат в среде разработки (PyCharm), чтобы получить подсветку синтаксиса, автоформат и прочие плюшки.
Вопрос: а как этот формат вообще называется? У него есть какая-нибудь спецификация?
Предположил, что это так и называется - configuration file. Но там нет ни слова про блоки в фигурных скобках.


Ответ

Так можно просто взять готовый плагин https://plugins.jetbrains.com/plugin/4415. Подсветка синтаксиса там есть
Configuration file syntax highlighting, auto-completion and inspections.

Функция нахождения максимума

Почему функция
int max1(int x,int y) { return x>y ? x : y; }
работает медленнее, чем
int max2(int x,int y) { return x?
Вот нашёл статью про это даже (в конце таблицы сравнения скоростей)
Вот моё сравнение:
#include #include #include #include #include #include int max1(int x,int y) { return x>y ? x : y; } int max2(int x,int y) { return x> v(size); std::for_each(v.begin(),v.end(),[](std::pair& x){x=std::make_pair(std::rand(),std::rand());}); unsigned int start1 = clock(); for (auto i : v) max1(i.first,i.second); unsigned int end1 = clock(); std::cout << end1-start1 << std::endl; unsigned int start2 = clock(); for (auto i : v) max2(i.first,i.second); unsigned int end2 = clock(); std::cout << end2-start2 << std::endl; }


Ответ

Я как раз недавно рассматривал подобный вопрос в этой статье (в самом конце).
У меня получилось так, что на архитектуре x86 всё зависит от порядка сравнения. Если x сравнивается с y, то компилятор даёт одну последовательность команд, а если наоборот, то другую последовательность тех же самых команд. Причина разницы в скорости, видимо, в особенностях микроархитектуры. Одна последовательность команд, видимо, лучше ложится на конвейер или ещё какие-то сторонние факторы влияют.
Это общая беда, наверное, всех процессоров Intel. Аналогично, я заметил, что команда inc eax будет работать медленнее, чем lea eax, [eax+1]. Подобных приколов, наверное, ещё много.

Перегрузка оператора “+” в шаблоне

Здравствуйте. Столкнулся с проблемой: не могу правильно перегрузить оператор сложения в шаблоне класса. Может кто показать мне мою ошибку? Тип данных массива в шаблоне может быть char,int, float, double. Должно поддерживаться сложение разных типов данных (т.е. если первый объект с параметром int, а второй - с параметром double, то метод должен возвращать объект с параметром double).
#pragma once template class Vector { T *data; size_t size; public: Vector(); Vector(size_t size); ~Vector(); size_t getSize(); void SetAll(); void ClearAll(); void SetVectorSize(size_t); T operator [](int); template< typename U > Vector & operator+(Vector &B); };
cpp файл:
#include "stdafx.h" #include "Vector.h" #include #include ... ... template template inline Vector & Vector::operator+(Vector& B) { if (sizeof(this->data[0]) > sizeof(B.data[0])) { Vector obj; } else { Vector obj; } obj.data[0] = 1; return obj; }


Ответ

Если я верно понял, что вы хотите, то решение примерно такое -
template Vector> operator+(const Vector&) const { Vector> x; // складываете, как вам надо ....... return x; }
Код
Vector a; Vector b; auto c = a+b; cout << typeid(c).name() << endl;
даст Vector
И еще - вы должны объявить этот оператор как возвращающий вектор нового типа, а не ссылку - иначе вы по сути вынуждены возвращать ссылку на свой объект, а его тип предопределен.
Update В принципе, можно как-то так - но, как мне кажется, это будет совсем не так красиво:
template auto operator+(const Vector&A) const { Vector x; return x; }
Т.е. даем компилятору самому решить, какой тип имеет сумма, и этот тип используем для типа возвращаемого значения.

Как правильно хранить куски текста в одном файле?

Есть файл с простой разметкой (как .ini). Разметка например такая:
[A1] 1=Текст A1-№1 2=Текст A1-№2
..........
[A2] 1=Текст A2-№1 2=Текст A2-№2
Как правильно и в какой папке хранить такие текстовые файлы, из которых я собираюсь формировать текст для вывода в TextView? Как формировать запрос на поиск нужного текста с такой разметкой? Может в JAVA есть аналог ini разметки?


Ответ

Для хранения произвольных файлов в структуре приложения Android выделены папки /assets и /res/raw. Доступ к этим ресурсам возможен только на чтение.
Различия кроются в способе доступа и организации хранения этих файлов.
Ресурсы в папке /assets могут иметь произвольную структуру подкаталогов, имен файлов и доступ к ним организуется через класс AssetManager, отдельные файлы не имеют идентификаторов в классе R.java, доступ к ним организуется напрямую по имени файла. Подробнее про ресурсы /assets
Ресурсы в папке /res/raw не могут иметь структуры подкаталогов, доступ к ним осуществляется по идентификатору, заданному в R.java, через синтаксис R.raw.*. Так же такие файлы несколько ограничены типом - разрешено хранить аудио, видео, html-страницы, текстовые файлы и тп. Подробнее о каталоге res/raw/
Кроме того, существует каталог /res/xml/, в котором можно хранить произвольные XML файлы (файлы структурированой информации, аналогичной той, которая представлена в вашем вопросе). Ресурсы так же имеют идентификаторы в R.java и обращаются к ним через R.xml.*. Подробнее
Перечисленные выше места хранения используются только для хранения статической информации - ее можно читать, но нельзя изменить или (до-)переписать. Если вам требуется доступ и на запись, то в таком случае файлы хранятся вне структуры приложения, на внешнем носителе. По умолчанию система Android выделяет для каждого приложения область на внешнем диске (по пути /data/data/), куда программа может записывать и считывать данные, но вы так же можете указать произвольное место работы (каталог), например, на SD-карте
Отличие в хранении в выделенной для приложения области в том, что эта область никаким образом недоступна другим приложениям (за исключением приложений с root-правами), так же при удалении приложения эта область удаляется вместе с ним. При хранении на SD-карте, доступ к данным может получить кто угодно и они не уничтожаются вместе с приложением при его деинсталяции.
Альтернативным способом хранения может быть запись значений в таблицу SQLite. Этот способ оправдан при необходимости делать произвольные выборки, а так же связывать различные данные (содержимое таблиц) между собой, так как организация работы с БД требует больших трудозатрат и дополнительных знаний в области СУБД - при простом хранении набора данных выгоднее и "дешевле" хранить его в структурированном файле. Тем не менее, вы так же можете подготовить БД и разместить ее в каталоге /assets, а затем скопировать на устройство (один из примеров). При этом база данных с которой могут работать классы Android может располагаться только в специальной выделенной области приложения по пути */data/data//database/*. При размещении в любом другом месте (например на SD-карте), Android не сможет с ней работать (либо вам придется написать свои классы работы с БД, которые смогут это делать). Размер самого файла БД несущественно больше размера хранимых в нем данных - этим в свете экономии места на диске можно пренебречь.
Аналоги INI файлов со встроенными в Android API инструментами для обработки - файлы форматов JSON и XML.
При довольно распространенном паттерне, когда требуется какой то заполненный данными файл, который потом необходимо модифицировать, поступают следующим образом: файл помещают в каталог /assets, при старте приложения его копируют оттуда в область выделенную приложению или на SD-карту и затем уже работают с скопированным файлом. Файл в /assets при этом остается в первоначальном состоянии и фактически является балластом, но ничего не поделаешь. Так же есть вариант создание файла динамически из кода, в некоторых случаях это позволяет существенно сократить объем приложения, то же относится и к заполнению таблиц SQLite.

Как выполнить действие после отрисовки Activity (fragment)

Есть ли метод с которого возможно воздействовать на только что отобразившуюся активность? Мне надо перезапустить view, как только она отрисуется. А отрисовать надо, чтобы узнать ее размер. После чего сразу выполнить другое действие с этими данными.


Ответ

К примеру у вас есть View mExampleView повесьте на нее обсервер, он сработает, как только вьюшка будет нарисована на экране. Когда будет вызван onGlobalLayout, вы можете узнать ее размер, затем отпишитесь и выполняйте нужный код.
ViewTreeObserver viewTreeObserver = mExampleView.getViewTreeObserver(); viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { mEaxampleView.getHeight(); // будет больше 0 mEaxampleView.getViewTreeObserver().removeGlobalOnLayoutListener(this); // Остальные действия } });

Время с 1900 года

Есть дата в секундах с 1 января 1900 года: -699848845. Как вычислить нормальную дату?


Ответ

Старое API (до Java 8):
Calendar cal = new GregorianCalendar(); cal.setTimeZone( TimeZone.getTimeZone( "UTC" ) ); // не указано, в какой зоне 1 января 1900, будет в UTC cal.clear(); cal.set( 1900, 0, 1 ); // январь - нулевой месяц
SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss.SSS zzzz" ); format.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
System.out.println( format.format( cal.getTime() ) ); // 1900-01-01 00:00:00.000 Coordinated Universal Time
cal.add( Calendar.SECOND, -699_848_845 ); System.out.println( format.format( cal.getTime() ) ); // 1877-10-27 21:32:35.000 Coordinated Universal Time
Новое API (Java 8 java.time):
LocalDateTime result = LocalDateTime.of( 1900, 1, 1, 0, 0 ) // январь - 1 месяц .plusSeconds( -699_848_845 ); System.out.println( result ); // 1877-10-27T21:32:35
Результат выводится в современном календаре (ISO-8601), без учета временной зоны. Для дремучего прошлого, возможно, придется подключать ThreeTen-extra, где есть реализация юлианского календаря, и разбираться в предмете подробнее.