Рассмотрим следующий код:CRTP и уникальные постоянные идентификаторы
#include <iostream>
#include <cstdlib>
#include <ctime>
struct BaseClass {
static int identifier() {
static int identifier_counter = 0;
return identifier_counter++;
}
};
template <class D>
struct Class: public BaseClass {
static int identifier() {
static int class_identifier = BaseClass::identifier();
return class_identifier;
}
};
struct A: public Class<A> { };
struct B: public Class<B> { };
int main() {
std::srand(std::time(0));
int r = std::rand()%2;
if(r) {
std::cout << "A: " << A::identifier() << std::endl;
std::cout << "B: " << B::identifier() << std::endl;
} else {
std::cout << "B: " << B::identifier() << std::endl;
std::cout << "A: " << A::identifier() << std::endl;
}
}
Это уменьшенный, но все же правдоподобным представление о проблеме.
Любой производный класс будет иметь конкретный идентификатор во время выполнения, а два экземпляра одного и того же типа будут иметь один и тот же идентификатор. Разумеется, это хорошее решение для такой проблемы.
К сожалению, эти идентификаторы зависят от порядка, в котором задействованы члены identifier
(мы можем легко его увидеть, выполнив несколько раз пример). Другими словами, учитывая два класса A
и B
, если происходит, что при запуске дважды программного обеспечения их члены identifier
вызывается в другом порядке, у них разные идентификаторы.
Моя проблема в том, что по некоторым причинам мне нужно хранить эти идентификаторы где-то и позволить им пережить одно исполнение, чтобы я мог рассуждать о первоначальных типах, когда приложение запускается еще раз и решит прочитать эти значения из хранилище.
Альтернативой было бы использовать hash_code от type_info
, но он страдает от других проблем. Другим решением будет принудительное обращение к членам identifier
во время загрузки приложения, но у этого также есть несколько недостатков.
Я хотел бы знать, есть ли все еще простое в использовании, хотя все еще элегантное решение, которое полностью прозрачно для разработчика, чтобы идентифицировать типы по нескольким исполнениям, так как один из них приведен для одного запуска приложения.
Что вы подразумеваете под внешним скриптом? Что-то вроде хранения идентификаторов в файле, который должен быть загружен при запуске программного обеспечения? – skypjack
Что-то похожее на способ использования идентификаторов rcs. Вы отмечаете свой класс с этим специальным атрибутом при первом создании, а скрипт изменяет источник, когда значение не задано. Это часть компиляции, а не среда выполнения. – SergeyA
Звучит интересно, поскольку я не могу загрузить что-либо во время выполнения. Мне жаль, что я не знаю, как работает rcs, но можете ли вы интегрировать свой ответ с некоторыми ссылками, чтобы лучше объяснить этот подход? В любом случае, спасибо, действительно оценил предложение. :-) – skypjack