Страницы

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

понедельник, 4 февраля 2019 г.

ключевое слово export

Для чего нужно ключевое слово export? Где реально его можно использовать?


Ответ

В стандарте C++ в примечании к параграфу №1 раздела 2.12 Keywords написано
[ Note: The export keyword is unused but is reserved for future use.—end note ]:
То есть это ключевое слово в настоящий момент нигде не используется, но зарезервировано для использования в будущем.
Ранее в стандарте C++ 2003 оно использовалось в определении шаблонов:
1 A template defines a family of classes or functions. template-declaration:
exportopt template < template-parameter-list > declaration ^^^^^^
но было исключено из стандарта. так как это средство не было задействовано многими компиляторами.
Вот пара цитат из с тандарта C++ 2003 (14 Templates), где имеются ссылка на это ключевое слово
6 A namespace-scope declaration or definition of a non-inline function template, a non-inline member function template, a non-inline member function of a class template or a static data member of a class template may be preceded by the export keyword. If such a template is defined in the same translation unit in which it is declared as exported, the definition is considered to be exported. The first declaration of the template containing the export keyword must not follow the definition. 8 Templates defined in an unnamed namespace shall not be exported. A template shall be exported only once in a program. An implementation is not required to diagnose a violation of this rule. A non-exported template must be defined in every translation unit in which it is implicitly instantiated (14.7.1), unless the corresponding specialization is explicitly instantiated (14.7.2) in some translation unit; no diagnostic is required. [Note: See also 14.7.2. ] An exported template need only be declared (and not necessarily defined) in a translation unit in which it is instantiated. A function template declared both exported and inline is just inline and not exported.

Преобразование индекса в соответствующий элемент перечисления

Есть перечисление с конструктором для задания индекса дня недели. Необходимо создать метод, преобразующий этот индекс в соответствующий день недели.
public enum DayOfWeek {
MONDAY(0), TUESDAY(1), WEDNESDAY(2), THURSDAY(3), FRIDAY(4), SATURDAY(5), SUNDAY(6);
int dayIndex;
DayOfWeek(int dayIndex) { setDayIndex(dayIndex); }
public int getDayIndex() { return dayIndex; }
public void setDayIndex(int dayIndex) { this.dayIndex = dayIndex; }
public static DayOfWeek valueOf (int index){ //метод для преобразования индекса дня недели в соответствующий элемент перечисления. } }
Подскажите как реализовать данный метод.


Ответ

Стоит воспользоваться YOUR_ENUM.values()[index]
Компилятор Java автоматически генерирует статический метод values() для каждого перечисления в java (вы не найдете метод values() в исходниках java).
Метод values() возвращает массив констант данного перечисление в том порядке в котором они определены. Данный метод используется при переборе элементов перечисления.
for (DayOfWeek p : DayOfWeek.values()) { System.out.printf("The day is %s, num = %d
", p, p.getDayIndex()); }
В итоге метод valueOf будет выглядеть так:
public static DayOfWeek valueOf (int index){ return DayOfWeek.values()[index]; }
В Main протестировать:
public static void main (String[] args) throws java.lang.Exception { System.out.print(DayOfWeek.valueOf(6)); }

С помощью рефлексии в java получить поле или метод

Все кажется просто:
Class c = user.getClass(); Field field = c.getField("id");
Но все крешется с ошибкой NoSuchFieldException Зато код:
Class c = user.getClass(); Field field = c.getDeclaredField("id");
Все работает. Так в чем разница? Во всех примерах используется 1 вариант но он не работает :(


Ответ

О, это одна из хитростей Java, getField - возвращает только публичные или унаследованные от суперклассов поля, а getDeclaredField - возвращает все поля класса... но не унаследованные от суперклассов поля (скажем вполне публичное поле, но доставшийся от суперкласса этот метод просто не увидит), так что если нужно вернуть действительно все нужно писать что-то вроде:
Field field; try { field = c.getField("id"); } catch (NoSuchFieldException e) { field = c.getDeclaredField("id"); }

Открытие doc, docx, odf, xlsx файла в терминале linux

Вопрос заключается в следующем: "Существует ли такие программы, позволяющие открыть doc, docx, odf файлы в терминале linux?". Понимаю, что теоретически это не возможно, в силу отсутствие возможности программной смены шрифта в терминале. Но! Что если, мне нужно, к примеру, тупо прочитать текст из файла, а под рукой нету десктопной машины? Или можно такой вариант: программа преобразовывает doc, docx, odf файл в tex-файл. P.S.: я так полагаю, что этот вариант открытия подобных файлов будет еще и экономнее десктопного относительно памяти.
С xlsx и подобными этому файлами тоже такой же вопрос встревает. Папа как-то рассказывал просто, что когда еще не было десктопных осей и граф оболочек, они использовали вместо doc-ов какую-то dos-овскую консольную прогу, и какие-то таблицы вместо excel-ей. Буду благодарен за ответ.
UPD: Вопрос закрыт


Ответ

Когда не было графических оболочек, тогда и и форматы были другие. Чем-то отчасти похожие на современный markdown
Файлы же конечно можно прочитать. Но именно прочитать - предварительно конвертировав в текстовый формат. Так Excel файлы можно перевести в CSV - а дальше смотри хоть в less, хоть awk или sed дальше преобразуй.
Файл Word конвертируются в обычный TXT - только текст и никакого форматирования. Можно и в RTF - тут оформление сохранится, но чтобы их читать нужен определенный навык :)
А с практической точки зрения задача довольно актуальная. Постоянно приходится решать задачи типа "У нас есть прайс-лист в Excel - мы хотим его автоматически загружать на сайта в базу данных". Соответственно помимо утилит консоли есть и куча библиотек под разные языки программирования - позволяющих открыть, прочитать, изменить и сохранить файлы этих форматов без взякого GUI.

php поменять точку на запятую

Обрабатываю числа функцией round
$kolall_itog = round(($kolall_itog + $kolall), 2);
Кодировка страницы utf-8. Как при выводе подменить точку на запятую?


Ответ

echo number_format($kolall_itog, 2, ',', '');
http://php.net/manual/ru/function.number-format.php

Как написать специализацию begin() для C-строки?

Хочу заставить работать цикл for(auto c:s) для обычной строки в духе C (0-завершенной). Работаю с Visual C++ 2015. Попытался специализировать шаблон begin()
template<> inline const char* begin(const char*& _Cont) noexcept { return _Cont; }
Увы, фокус не удался - ошибка C2912, явная специализация (см. выше) не является специализацией функции-шаблона. Соответственно, вопрос первый - почему?
Если просто написать перегрузку
inline const char* begin(const char*& Cont) { return Cont; }
ничуть не лучше - ошибка C3312, не найдена вызываемая функция begin для типа const char*. Замена в перегрузке begin(const char*& Cont) на begin(const char* Cont), само собой, не спасает.
Вопрос второй - вроде, по всем канонам, при разрешении шаблонов и перегрузки должна быть выбрана перегрузка? Или здесь не просто вызов функции и это правило не работает?
Ну, и третий вопрос - это вообще можно, то, что я хочу, или нет? и если да - то как?


Ответ

Всё ведь совсем просто, не понимаю зачем Вы полезли в дебри шаблонов:
#include
const char* begin(const char* str) noexcept { return str; }
const char* end(const char* str) noexcept { int count = strlen(str); return str + count; }
int main() { for(auto c : "Hello Moscow!") std::cout << c; std::cout << "
"; }

На деле оказалось не так просто. Пример выше будет работать даже если убрать мою реализацию begin/end(т.е. она не используется). Видимо есть перегрузка для массивов в std для begin/end, а вот чтобы for заработал для const char* нужно написать следующий код:
#include
namespace std { const char* begin(const char* str) noexcept { return str; }
const char* end(const char* str) noexcept { int count = strlen(str); return str + count; } }
int main() { const char* str = "Hello Moscow!"; for(auto c: str) std::cout << c; std::cout << "
"; }
Но с этим кодом есть проблема: стандарт явно запрещает засорять namespace std подобными реализациями. Поэтому, в силу чисто академического интереса можно и посмотреть на это, но вот использовать лучше не стоит(хотя Вы вряд ли нарвётесь на неприятности). По другому сделать не получится, потому как for внутри себя, скорее всего, использует std::begin/std::end

Обновление 2: всё вышесказанное относится лишь к студии. В других компиляторах это не работает, а это значит, что std::begin/std::end могут быть вызваны в студии, но для этого кода они не будут вызваны ни в clang ни в gcc. Что это всё значит? Это значит, что for для const char* работать не будет.

Обновление 3: Почему не работает попытка специализации шаблона(как в вопросе) внутри namespace std?(из комментариев). Дело в том, что в заголовках студии есть следующие перегруженные функции для std::begin: Раз
template auto inline begin(_Container& _Cont) -> decltype(_Cont.begin())
Два
template auto inline begin(const _Container& _Cont) -> decltype(_Cont.begin())
И три
template inline_CONST_FUN _Ty *begin(_Ty (&_Array)[_Size]) _NOEXCEPT
Так вот, написав:
template<> inline const char* begin(const char*& _Cont) noexcept
Мы начинаем проверять, какой шаблон мы специализируем. Начнём с первого — проверка не проходит, почему? Потому что decltype(_Cont.begin()) не скомпилируется, т.к. у const char* нет метода begin(), поэтому срабатывает SFINAE и вариант отбраковывается. То же происходит и со вторым вариантом. Остается третий вариант, который принимает массив и из него извлекат 2 необходимых параметра шаблона, но у нас ведь указатель, поэтому этот вариант тоже отбраковывается. И у нас остается ... ничего! Вот и ошибка компилятора, что специализация не имеет общего случая, который специализировать.
Приведу пример, как можно сделать специализацию для первого и третьего случая:
#include #include #include
namespace std { template<> int *begin(int(&_Array)[50]) noexcept { std::cout << "Yeah!
"; return nullptr; }
template<> auto inline begin(const std::vector& _Cont) -> decltype(_Cont.begin()) { std::cout << "Beah!
"; return _Cont.begin(); } }
int main() { int a[50]; std::begin(a); std::begin(std::vector{}); }
Но этот код не компилируется 2015 студией. Причина мне не ясна(ей не нравится специализация для контейнера), видимо баг в студии(создал bug-report), т.к. другие компиляторы такой код компилируют на ура(для clang надо будет поправить noexcept).

Удалить перенос строки, если строка не пустая

Как средствами shell удалить перенос строки только в том случае, если строка не пустая?
Допустим есть файл, содержащий
q w e
r t
y
Из него необходимо получить файл, содержащий
qwe
rt
y


Ответ

$ cat file | sed 's/^$/

/' | tr -d '
' | tr '
' '
'
сначала в пустые строки вставляем пару символов carriage return (0x0d,
), которые на последнем шаге заменим на символы line feed (0x0a,
).
затем удаляем все символы line feed
последний шаг: заменяем все carriage return на line feed

вместо carriage return можно использовать любой другой символ, который заведомо не встречается в исходном файле.

результирующий файл получится без завершающего символа
, что не принято у текстовых файлов. чтобы этого избежать, можно в программе для sed сразу добавлять в конце последней строки символ-подмену:
$ cat file | sed 's/^$/

/;$s/$/
/' | tr -d '
' | tr '
' '
'

обновление
в общем-то, можно обойтись только вызовом sed, без символа-подмены, и без tr, но программа для sed получается несколько громоздкой:
$ cat /tmp/file | sed -n '/^$/!H;/^$/{x;s/
//g;/^$/!s/$/
/;p};${x;s/
//g;p}'