Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, rg45, Вы писали:
J>Я сделал в свое время похожую штуку — и напоролся на ограничение рекурсии инстанцирования для сколько-нибудь больших файлов. Но это было давно, может, сейчас это и не проблема уже...
Сейчас это тоже проблема. Я вот буквально вчера мерял на 2015-й студии — максимально допустимая глубина такой рекурсии — 495. Наверное, этим можно как-то управлять, но предел будет в любом случае.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, rg45, Вы писали:
J>>Я сделал в свое время похожую штуку — и напоролся на ограничение рекурсии инстанцирования для сколько-нибудь больших файлов. Но это было давно, может, сейчас это и не проблема уже...
R>Сейчас это тоже проблема. Я вот буквально вчера мерял на 2015-й студии — максимально допустимая глубина такой рекурсии — 495. Наверное, этим можно как-то управлять, но предел будет в любом случае.
Да, тут, разве что, вставлять промежуточные UPDATE, когда такая ошибка вылазит. Или какой-нибудь
Здравствуйте, rg45, Вы писали:
J>>Я сделал в свое время похожую штуку — и напоролся на ограничение рекурсии инстанцирования для сколько-нибудь больших файлов. Но это было давно, может, сейчас это и не проблема уже... R>Сейчас это тоже проблема. Я вот буквально вчера мерял на 2015-й студии — максимально допустимая глубина такой рекурсии — 495. Наверное, этим можно как-то управлять, но предел будет в любом случае.
Управляется каким-то ключом (я, помню, игрался с этим давно).
Вот именно поэтому __COUNTER__ предпочтительнее __LINE__. Особенно, если мало кто будет им пользоваться.
Здравствуйте, jazzer, Вы писали:
J>Я сделал в свое время похожую штуку — и напоролся на ограничение рекурсии инстанцирования для сколько-нибудь больших файлов. Но это было давно, может, сейчас это и не проблема уже...
Вместо линейной рекурсии можно сделать деревянную!
template<int I> struct int_ { static constexpr int value = I; };
using int_0 = int_<0>;
using int_1 = int_<1>;
template<int I> struct point : int_0 {};
#define TAG_IT() template<> struct point<__COUNTER__> : int_1 {};
template<int L, int N> struct sumpoints;
template<int L, int H, int N> using splitsum = int_< sumpoints<L,H>::value + sumpoints<L+H,N-H>::value >;
template<int L> struct sumpoints<L, 0> : int_0 {};
template<int L> struct sumpoints<L, 1> : point<L> {};
template<int L, int N> struct sumpoints : splitsum<L, N/2, N> {};
// лучше разбивать не пополам, а по старшему биту, - это даст меньше сочетаний <L,N> при массовом использовании
// и, соответственно, меньше воплощений шаблона
// но я сходу не вспомнил формулу для его нахождения#define GET_IT() (sumpoints<0, __COUNTER__>::value)
constexpr int x = GET_IT(); // __COUNTER__ = 1, x = 0
constexpr int y = GET_IT(); // __COUNTER__ = 2, y = 0
TAG_IT(); // __COUNTER__ = 3
TAG_IT(); // __COUNTER__ = 4
TAG_IT(); // __COUNTER__ = 5
constexpr int z = GET_IT(); // __COUNTER__ = 6, z = 3
К> // лучше разбивать не пополам, а по старшему биту, — это даст меньше сочетаний <L,N> при массовом использовании К> // и, соответственно, меньше воплощений шаблона К> // но я сходу не вспомнил формулу для его нахождения
Наверно, можно вот такое
constexpr int pivot(unsigned N) {
int r = N & (N-1); // обнуление младшего битаreturn r ? r : N/2;
}
То есть, мы просто с другого направления заедем при построении поразрядного дерева.
Например, нам надо взять суммы <0,7>, <0,11> и <0,12>.
Это не готовая реализация CTC, а только прототип, упрощенный до предела так, чтобы видна была идея.
Достоинства:
Не используются никакие константы препроцессора (__LINE__, __COUNTER__ и пр);
Не используется специализации шаблона основного класса счетчика, что допускает его применение не только в пространстве имен, но и в теле классов (до C++17 спещиализация вложенных классов должна была выполняться только в обрамляющем пространстве имен);
Возможность одновременного использования множества независимых счетчиков;
Огранченность областью видимости. Счетчики из вложенных областей видимости не конфликтуют с одноименными счетчиками из охватывающих областей видимости;
Автоматический инкремент при каждом обращении к счетчику.
Недостатки:
Ограничение максимального значения счетчика, довольно низкое. Над этим заморачиваться не нужно, решение уже найдено; ГЛАВНАЯ ПРОБЛЕМА: привести счетчик в соответствие требованиям стандарта! Сейчас эта реализация работает только на msvc. Как я ни бился, мне так и не удалось заставить это заработать под gcc. Причина ясна — дружественная функция не появляется в окружающем пространстве имен.
CREATE_CTC(ctc1)
enum class Foo
{
zero = GET_CTC(ctc1),
one = GET_CTC(ctc1),
two = GET_CTC(ctc1),
three = GET_CTC(ctc1),
four = GET_CTC(ctc1),
five = GET_CTC(ctc1),
};
--
Не можешь достичь желаемого — пожелай достигнутого.
Внутри каждой из специализаций разместить набор статических свойств, специфичных, например, для членов какого-то класса. Или для элеметнов списка типов, или для перечисления, или для элементров интрузивного профайлера, или... После этого эти наборы специализаций можно использовать для авотматической генерации, например, классов сериализации-десериализации, конверторов, аксессоров к базам данных... В общем, дофига всего.
Этот подход позволяет сколько угодно добавлять новые структуры данных, изменять и расширять существующие, не меняя при этом процедур работы с этими данными (сериализация/десериализация, вычитка/запись из/в БД, ввод-вывод, конверторы и пр).
--
Не можешь достичь желаемого — пожелай достигнутого.