Список целых на этапе компиляции с проверкой
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 26.12.17 18:39
Оценка:
Здравствуйте!

Есть желание получить на этапе компиляции список чисел, с возможностью добавления элементов с проверкой на существование — т.е. если есть уже значение, то компиляция ломается.
Пока в голову ничего не идет Реально ли такое сделать на 11ом стандарте? Подскажите, в какую сторону копать..


А вообще, может есть и какое-то другое решение для проблемы. Есть фиксированные ресурсы различных типов, они в разных частях софтины используются. Каждый ресурс может быть использован один раз, но из за ошибок могут быть попытки множественного использования, которые надо пресекать. Сейчас это проверяется в рантайме, что мне не очень нравится
Маньяк Робокряк колесит по городу
Re: Список целых на этапе компиляции с проверкой
От: Pzz Россия https://github.com/alexpevzner
Дата: 26.12.17 18:48
Оценка: 4 (1)
Здравствуйте, Marty, Вы писали:

M>Пока в голову ничего не идет Реально ли такое сделать на 11ом стандарте? Подскажите, в какую сторону копать..


Реально. Система C++ темплейтов — тьюринг-полная.

Ну, например, создай какой-нибудь пустой темплейтный тип, параметризованный целым числом, и добавляй для каждого конкретного числа специализацию. Два раза для одного и того же числа компилятор тебе этого сделать не даст.

M>А вообще, может есть и какое-то другое решение для проблемы. Есть фиксированные ресурсы различных типов, они в разных частях софтины используются. Каждый ресурс может быть использован один раз, но из за ошибок могут быть попытки множественного использования, которые надо пресекать. Сейчас это проверяется в рантайме, что мне не очень нравится


Если это проверяется в процессе иницаилизации программы, это не так уж и плохо. Главное, просто и понятно, и взрывается сразу на старте. Хуже, если проверка устроена так, что взорваться может в любой момент.
Re[2]: Список целых на этапе компиляции с проверкой
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 26.12.17 18:59
Оценка:
Здравствуйте, Pzz, Вы писали:


Pzz>Ну, например, создай какой-нибудь пустой темплейтный тип, параметризованный целым числом, и добавляй для каждого конкретного числа специализацию. Два раза для одного и того же числа компилятор тебе этого сделать не даст.


Хм. Макросом?


Pzz>Если это проверяется в процессе иницаилизации программы, это не так уж и плохо. Главное, просто и понятно, и взрывается сразу на старте. Хуже, если проверка устроена так, что взорваться может в любой момент.


В принципе, ты наверно прав. Да и в компайл тайм не получится — использование-то может быть из разных единиц трансляции
Маньяк Робокряк колесит по городу
Re[3]: Список целых на этапе компиляции с проверкой
От: watchmaker  
Дата: 26.12.17 19:26
Оценка: 4 (1)
Здравствуйте, Marty, Вы писали:

M> Да и в компайл тайм не получится — использование-то может быть из разных единиц трансляции


Так потом есть ещё ведь этап сборки.

Общее направление: пусть "использование" инстанциирует экземпляр примерно такой переменной: template <int n> int once = -1;, где значение параметра шаблона (это, кстати, не обязательно int) зависит от типа ресурса (или прямо им и является).

Тогда, хотя все единицы трансляции и скомпилируются успешно, линкер не сможет собрать программу, если в ней будут совпадения.
Re[4]: Список целых на этапе компиляции с проверкой
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 26.12.17 19:28
Оценка:
Здравствуйте, watchmaker, Вы писали:


W>Так потом есть ещё ведь этап сборки.


W>Общее направление: пусть "использование" инстанциирует экземпляр примерно такой переменной: template <int n> int once = -1;, где значение параметра шаблона (это, кстати, не обязательно int) зависит от типа ресурса (или прямо им и является).


W>Тогда, хотя все единицы трансляции и скомпилируются успешно, линкер не сможет собрать программу, если в ней будут совпадения.


Спасибо, идея годная
Маньяк Робокряк колесит по городу
Re: Список целых на этапе компиляции с проверкой
От: Кодт Россия  
Дата: 27.12.17 10:17
Оценка:
Здравствуйте, Marty, Вы писали:

M>А вообще, может есть и какое-то другое решение для проблемы. Есть фиксированные ресурсы различных типов, они в разных частях софтины используются. Каждый ресурс может быть использован один раз, но из за ошибок могут быть попытки множественного использования, которые надо пресекать. Сейчас это проверяется в рантайме, что мне не очень нравится


Ну, можно завести единый список идентификаторов ресурсов.
Это или один большой .h-файл с уникальными номерами (банально, энум без явных значений; или генерировать .h скриптом; или валидировать его скриптом же);
или набор .h-файлов и один диспетчерский файл с заведомо непересекающимися диапазонами
// диспетчерский хедер

enum { ID_RESOURCES__RANGE = 10000 };

enum ID_RESOURCES__COUNTERS {
  ID_RESOURCES_ONE__COUNTER,
  ID_RESOURCES_TWO__COUNTER,
  .....
};

// хедер конкретных ресурсов

enum RESOURCES_ONE {
  ID_RESOURCES_ONE_FIRST = ID_RESOURCES_ONE__COUNTER * ID_RESOURCES__RANGE - 1,

  ID_RESOURCES_ONE_ONE,
  ID_RESOURCES_ONE_TWO,
  .....

  ID_RESOURCES_ONE_LAST,
  ID_RESOURCES_ONE_ASSERT = 1 / (ID_RESOURCES_ONE_LAST - ID_RESOURCES_ONE_FIRST < ID_RESOURCES__RANGE ? 1 : 0)
};

Заодно, все ресурсы окажутся перед глазами, — не надо будет грепать все исходники в поисках объявлений.

При этом у тебя не будет никаких ограничений вида "определение ресурса должно лежать строго внутри единицы трансляции, а наружу — только по ссылке на объявление",
как это было бы при использовании специализаций шаблонов, которые предложил watchmaker. (Да ещё надо побороться, чтобы компилятор и линкер умели диагностировать нарушение ODR, а не тупо посокращали якобы-инлайны).

P.S.
Какой смысл ты вкладываешь в слова "каждый ресурс может быть использован один раз"?
— определён в одной точке исходников
— прочитан в одной точке исходников и больше нигде
— прочитан единожды за запуск программы
— иное?
Ну и заодно, какого рода эти ресурсы?
Перекуём баги на фичи!
Re[5]: Список целых на этапе компиляции с проверкой
От: rg45 СССР  
Дата: 27.12.17 12:08
Оценка:
Здравствуйте, Marty, Вы писали:

W>>Общее направление: пусть "использование" инстанциирует экземпляр примерно такой переменной: template <int n> int once = -1;, где значение параметра шаблона (это, кстати, не обязательно int) зависит от типа ресурса (или прямо им и является).

W>>Тогда, хотя все единицы трансляции и скомпилируются успешно, линкер не сможет собрать программу, если в ней будут совпадения.

M>Спасибо, идея годная


Сразу обрати внимание на ограничение: такие специализации можно сделать либо в том же, либо в обрамляющем пространстве имен (с явной спецификацией пространства имен). Если окажется, что "использование" происходит в каком-нибудь вложенном или несвязанном пространстве имен, то это может серьезно осложнить задачу. И в области видимости классов специализации делать не разрешается по стандарту, хоть некоторые компиляторы (msvc, например) и поддерживают эту возможность.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 27.12.2017 13:07 rg45 . Предыдущая версия . Еще …
Отредактировано 27.12.2017 12:32 rg45 . Предыдущая версия .
Отредактировано 27.12.2017 12:10 rg45 . Предыдущая версия .
Re[6]: Список целых на этапе компиляции с проверкой
От: watchmaker  
Дата: 27.12.17 13:27
Оценка:
Здравствуйте, rg45, Вы писали:

R>Сразу обрати внимание на ограничение: такие специализации можно сделать либо в том же, либо в обрамляющем пространстве имен (с явной спецификацией пространства имен). Если окажется, что "использование" происходит в каком-нибудь вложенном или несвязанном пространстве имен, то это может серьезно осложнить задачу. И в области видимости классов специализации делать не разрешается по стандарту, хоть некоторые компиляторы (msvc, например) и поддерживают эту возможность.



Зачем делать явную специализацию? Это какое-то ненужное переусложнение.

Достаточно в месте "использования" потрогать переменную любым способом (который ODR-used).
Ну то есть написать в once.h
#pragma once 
template <typename T> int instance_me_only_once = 0;

А потом в люом месте включать этот заголовочный файл и трогать переменную:
#include <once.h>

namespace Whatever {
  template <class Foo>
  struct Bar {
    Bar() {
      ++instance_me_only_once<Foo>; 
      Use<Foo>();
    }
  }
}


Теперь если в другой единице трансляции тоже сделать ++instance_me_only_once<Foo>, то программа не соберётся.
Отредактировано 27.12.2017 15:43 watchmaker . Предыдущая версия .
Re[7]: Список целых на этапе компиляции с проверкой
От: rg45 СССР  
Дата: 27.12.17 14:21
Оценка:
Здравствуйте, watchmaker, Вы писали:


W>Зачем делать явную специализацию? Это какое-то ненужное переусложнение.

W>Достаточно в месте "использования" потрогать переменную любым способом (который ODR-used).
W>Ну то есть написать в once.h
#pragma once 
W>template <typename T> int instance_me_only_once = 0;
W>

W>А потом в люом месте включать этот заголовочный файл и трогать переменную:
W>#include <once.h>
W>namespace Whatever {
W>  template <class Foo>
W>  struct Bar {
W>    Bar() {
W>      ++instance_me_only_once<Foo>; 
W>      Use<Foo>();
W>    }
W>  }
W>}
W>

W>Теперь если в другой единице трансляции тоже сделать ++instance_me_only_once<Foo>, то программа не соберётся.

Чего-то я не догоняю. Как может переменная, значение которой изменяется в runtime иметь какое-нибудь влияние на компиляцию? Что должно помешать этой переменной быть использованной повторно и какая ошибка при этом ожидается?

Вот я пробую промоделировать ситуацию на msvc-14.0. В существующий консольный проект добавляю такой вот заголовок once.h и помещаю обращение к instance_me_only_once<int> в две функции, определенные в разных единицах трансляции:
   std::cout << "++instance_me_only_once<int> = " << ++instance_me_only_once<int> << std::endl;


получаю выхлоп:

++instance_me_only_once<int> = 1
++instance_me_only_once<int> = 2


Что я упускаю из виду?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[8]: Список целых на этапе компиляции с проверкой
От: watchmaker  
Дата: 27.12.17 15:42
Оценка: 16 (1)
Здравствуйте, rg45, Вы писали:


R>Чего-то я не догоняю.


Извини, это я что-то запутался и перепутал эффекты от явного инстанциирования с ord-use. Твой комментарий к предыдущему сообщению верен.
Re[2]: Список целых на этапе компиляции с проверкой
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 27.12.17 17:39
Оценка:
Здравствуйте, Кодт, Вы писали:


К>P.S.

К>Какой смысл ты вкладываешь в слова "каждый ресурс может быть использован один раз"?
К>- определён в одной точке исходников
К>- прочитан в одной точке исходников и больше нигде
К>- прочитан единожды за запуск программы
К>- иное?
К>Ну и заодно, какого рода эти ресурсы?

Изначально, это STMка, на борту пяток UARTов, для них есть пять глобальных соответствующих объектов, при необходимости UART передается в task (FreeRTOSный), который настраивает/включает этот UART и дальше с ним и работает. Сейчас у UART'а есть mutex, который захватывается на этапе инициализации, и если занят, то приехали. Мьютекс там конечно легкий по размеру, а потом в работе не используется, но все равно некрасиво. Без FreeRTOS тоже используется, несколько по другому, и так как своих мьютексов нет, там другая корявая проверка. Мне всё это не очень нравится.

Пока эту проблему обдумывал, пришли еще идеи, и подумалось, что неплохо было бы иметь универсальное решение — несколько областей, в которых нужно проверять уникальность использования — указателей, числовых идентификаторов и тп.

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

UPD Есть еще идея добавить немного COMа
Без управления созданием и временем жизни, просто функциональность QueryInterface. UIDы как-то жирновато для этого использовать, целые числа выглядят приятнее. В этом случае можно вести реестр этих UIDов в одном месте, но интереснее обдумать идею, когда каждый создает UIDы на свой вкус
Маньяк Робокряк колесит по городу
Отредактировано 27.12.2017 17:46 Marty . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.