Экспортируйте постоянную времени компиляции, ограничивая видимость класса - PullRequest
0 голосов
/ 24 января 2019

Я использую компилятор до C ++ 11 и пытаюсь «экспортировать» константу, не раскрывая классы, из которых эта константа вычисляется.

// A.hpp ----------------------
struct A{
...
};
// B.hpp ----------------------
struct B{
...
};

// Manager.hpp ------------------
#include "Manager.hpp"
template <size_t a, size_t b>
struct StaticMax
{
   enum { value = a>b ? a : b };
}
class Manager
{
public:
    static const size_t OverlayDataSize;
 ...
};
// manager.cpp ------------------
#include "A.hpp"
#include "B.hpp"
// I want the following constant to be available to anyone
// that includes Manager.hpp, but the classes A and B should not
// be visible to anyone else except class Manager
const size_t Manager::OverlayDataSize = StaticMax<sizeof(A),sizeof(B)>::value;

// otherfile.hpp -------------------
#include "Manager.hpp"
struct OverlayData
{
    // shared state goes here
    uint8 gameState;
    uint8 specificState[Manager::OverlayDataSize];
};
class NvRam
{
    void Write(OverlayData& serializedState);
    ....
}

Приведенный выше кодне компилируется и приводит к:

ошибка: «Manager :: OverlayDataSize» не является допустимым аргументом шаблона для типа «unsigned int», потому что это неконстантное выражение

Что уже странно, поскольку Manager::OverlaySize определенно равен const и его значение вычисляется во время компиляции.Но согласно этому вопросу, если объявление const и его определение не находятся в одном месте, то компилятор не может использовать его как константу.Ошибка сохраняется, даже если вы используете глобальную переменную, объявленную с extern.Я мог бы рассчитать максимальный размер по-разному, используя объединение (но тогда структурам A и B не разрешено иметь конструкторы), но это не проблема, я все еще не могу экспортировать эту константу, чтобы быть доступной ввремя компиляции без раскрытия структур A и B для всех.Конечно, я могу обойти весь вопрос, сделав структуру DataOverlay немного более сложной и используя new uint8[Manager::OverlayDataSize]; во время выполнения и быть в состоянии поддерживать строгую изоляцию.Но я стараюсь, чтобы это было сделано статически во время компиляции.

Итак, как «экспортировать» константу времени компиляции, поддерживая строгое разделение между структурами A и B и пользователями Manager

1 Ответ

0 голосов
/ 24 января 2019

Вот (довольно некрасивое) решение.

Основная проблема в том, что вам нужны только значения A и B, которые являются константами, но вы вынуждены включить полное определение.Решением было бы вручную рассчитать размер и записать его в нужном месте.

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

Для этого вы можете написать генератор кода, который генерирует такой код в заголовочном файле:

const size_t OverlayDataSize = /* the calculated size */;

и вызывать эту программу каждый раз, когда вы перестраиваете весь проект.(Например, написав Makefile.)

Этот генератор может включать A.hpp и B.hpp, вычислить max(sizeof(A), sizeof(B)) и запустить printf или что-то подобное для написания сгенерированного кода.Другие исходные файлы должны только #include сгенерированный источник.

Поскольку в C ++ нет модульной системы (которая позволит вам скрывать некоторые внутренние сущности) или полного средства метапрограммирования (которое позволяет нам писать некоторый код, который генерирует другой код), я могу думать только об этомдовольно некрасивый способ добиться этого.Но в любом случае, это должно работать.

...