2013-03-21 2 views
5

Я создал класс, который выглядит как массив, но вместо того, чтобы хранить данные в самой программе, он передает байт из файла (чтобы уменьшить влияние ОЗУ). Теперь у меня есть все это работает, но программист должен определить класс, используя следующее:Создание параметров шаблона во время компиляции

#define CreateReadOnlyBlock(name, location, size, ...)   \ 
template<>              \ 
const unsigned int ReadOnlyBlock<location, size>::Data[]  \ 
    __asm__(".readonly__" #location "__" #name)    \ 
    = { __VA_ARGS__ };           \ 
ReadOnlyBlock<location, size> name; 

Пример:

//A read only array of {0, 1, 2, 3} 
CreateReadOnlyBlock(readOnlyArray, 0, 4, 0, 1, 2, 3); 

Обратите внимание, что это для встроенного процессора, и директива ASM проходит через инструмент в ассемблере для создания файла только для чтения.

Итак, вот мой вопрос: как я могу устранить переменные «местоположение» и «размер»? Я ненавижу, что программисту приходится вводить их вручную, и он предпочитает какой-то способ генерации данных во время компиляции. Таким образом, вместо программиста необходимости печатать:

//A read only array at location 0 of {0, 1, 2, 3} 
CreateReadOnlyBlock(readOnlyArray1, 0, 4, 0, 1, 2, 3); 
//A read only array at location 4 of {4, 5, 6, 7} 
CreateReadOnlyBlock(readOnlyArray2, 4, 4, 4, 5, 6, 7); 

Они могли бы просто напечатать:

CreateReadOnlyBlock(readOnlyArray1, 0, 1, 2, 3); 
CreateReadOnlyBlock(readOnlyArray2, 4, 5, 6, 7); 

И соответствующие константы будут генерироваться. В основном я ищу способ генерации и размещения этих констант на основе предыдущих определений во время компиляции. C++ 11 - честная игра, я просто не очень хорошо знаком с ней (что-то с constexpr кажется правдоподобным?). Кроме того, C-Preprocessor тоже в порядке, если он не делает его более уродливым, чем он есть. Это возможно?

EDIT для ясности:

В классе ReadOnlyBlock есть этот метод:

template<const int _location, const int _size> class ReadOnlyBlock 
    { 
     ... 
     unsigned int operator[] (size_t index) 
     { 
      return LoadFromROM(index + _location); 
     } 
    } 

Существует внутренняя взаимозависимость между переменным местоположением и файлом ROM, который я не могу думать о том, как сломать. I do также имеют полный контроль над цепочкой инструментов, но мне нужен способ передать инструмент ассемблера, как построить файл, а также указать код C++, где блоки лежат в файле.

Другой EDIT:

файл и его блоки могут быть довольно большой, так же, как 1k слова, так много препроцессора магии может рухнуть при условии, что. Кроме того, спасибо всем за помощь до сих пор!

+0

Параметр '# location' в части '__asm__' действительно убивает его. Вам действительно нужно это, или вы будете довольны решением всего остального? –

+2

Размер прост, но для местоположения потребуется контекст. Создание экземпляра шаблона является функциональным языком, и результат создания может варьироваться только в зависимости от того, что вы передаете. Если вы связываете такие блоки или создаете память в одном большом шаблоне, это может быть сделано. Т.е. создайте «кортеж» только для чтения массивов, каждый из которых имеет местоположение и размер, начиная с некоторого места и упаковывая. – Yakk

+0

Так что, возможно, я должен был включить причину этого. Перегруженный оператор [] в классе ReadOnlyBlock вызывает LoadFromROM (индекс + местоположение); Инструмент создает файл только для чтения, который имеет каждый блок в каждом указанном месте, и класс знает, что нужно загрузить с этого места. Я не могу придумать способ устранить эту взаимозависимость, но у меня есть полный контроль над инструментом, а также код доступа, поэтому его изменение не может быть и речи. –

ответ

1

Я до сих пор не вижу полное решения для генерации имени (что #location фрагмента), но в остальном, я думаю, вы могли бы использовать что-то вроде это:

template< std::size_t Line > 
struct current_location : current_location< Line - 1 > {}; 

template<> 
struct current_location<0> : std::integral_constant< std::size_t, 0 > {}; 

#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int)) 

#define CreateReadOnlyBlock(name, ...)       \ 
template<>              \ 
const unsigned int ReadOnlyBlock<        \ 
    current_location<__LINE__-1>::value, NUMARGS(__VA_ARGS__) \ 
>::Data[]              \ 
    __asm__(".readonly__" #name)        \ 
    = { __VA_ARGS__ };           \ 
ReadOnlyBlock<current_location<__LINE__-1>::value,    \ 
       NUMARGS(__VA_ARGS__)> name;      \ 
template<>              \ 
struct current_location<__LINE__>        \ 
    : std::integral_constant<std::size_t,      \ 
     current_location<__LINE__-1>::value+NUMARGS(__VA_ARGS__)> \ 
{}; 
+0

Это прекрасно! Огромное спасибо. На самом деле я не уверен, что мне больше нужно #location, поскольку это, похоже, все равно помещает данные в сплошной последовательный блок. Я немного обеспокоен тем, что компилятор может переупорядочить все, хотя мне нужен идентификатор местоположения. В этом случае я бы просто положил местоположение в качестве первого индекса в массиве и получил инструмент для его удаления. Не красиво, но эй это работает! Еще раз спасибо! –

0

Может быть, хватать немного, но возможно ли это с помощью вариативных шаблонов вместо va_args? Что-то вроде

template <typename T1, ... TV> 
class ReadOnlyBlock 
{ 
    static unsigned int Data[sizeof(TV) + 1]; 
}; 

В основном, везде, где вам нужно «местоположение», используйте T1. В любом месте вам нужно «размер», используйте sizeof (TV) + 1. У вас нет подходящего компилятора, чтобы проверить это, но, возможно, это нужно рассмотреть ...

+0

На самом деле это не данные, которые меня убивают прямо сейчас, но спасибо за предложение! Я могу преобразовать его в вариативные шаблоны позже, я просто более комфортно с препроцессором C и просто пытаюсь заставить его работать. –

0

Это может помочь. Я написал кое-что для подсчета блоков. может добавить DEF_BLOCK(size) для объявления блока.Вы можете попробовать переписать мой пример, чтобы выделить данные в моих блоках

template<size_t ID> 
struct block_t 
{ 
    enum{location = 0}; 
}; 

#define LAST_BLOCK struct last_block_t{enum{id=__COUNTER__-1};}; 

#define SPEC2(ID, SIZE) template<> struct block_t<ID>{enum{location = block_t<ID-1>::location + SIZE, prev_block = ID-1, size = SIZE};} 
#define SPEC(ID, SIZE) SPEC2(ID, SIZE) 

#define DEF_BLOCK(SIZE) SPEC(__COUNTER__, SIZE) 

DEF_BLOCK(10); 
DEF_BLOCK(11); 
LAST_BLOCK; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    std::cout << block_t<last_block_t::id>::location << std::endl; 
    return 0; 
} 
0

Если имеет место следующее:

  • Вы не используете __COUNTER__ elswhere
  • Все массивы имеют максимальную длину 5
  • Все массивы определяются в том же самом файле

Тогда вы можете сделать это:

#include <iostream> 

#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, N, ...) N 
#define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1) 

template <int... Args> 
struct arg_counter { 
    enum { count = sizeof...(Args) }; 
}; 

#define INC_COUNTER1 arg_counter<-1>::count 
#define INC_COUNTER2 arg_counter<-1, __COUNTER__>::count 
#define INC_COUNTER3 arg_counter<-1, __COUNTER__, __COUNTER__>::count 
#define INC_COUNTER4 arg_counter<-1, __COUNTER__, __COUNTER__, __COUNTER__>::count 
#define INC_COUNTER5 arg_counter<-1, __COUNTER__, __COUNTER__, __COUNTER__, __COUNTER__>::count 

#define INC_COUNTER_IMPL2(count, ...) INC_COUNTER ## count 
#define INC_COUNTER_IMPL(count, ...) INC_COUNTER_IMPL2(count, __VA_ARGS__) 
#define INC_COUNTER(...) INC_COUNTER_IMPL(VA_NARGS(__VA_ARGS__), __VA_ARGS__) 

// removed: __asm__(".readonly__" #location "__" #name) 
#define CreateReadOnlyBlockImpl(name, location, size, ...)  \ 
    template<>             \ 
    const unsigned int ReadOnlyBlock<location, size>::Data[]  \ 
    = { __VA_ARGS__ };           \ 
    ReadOnlyBlock<location, size> name; 


#define CreateReadOnlyBlock(name, ...)         \ 
    CreateReadOnlyBlockImpl(name, __COUNTER__, INC_COUNTER(__VA_ARGS__), __VA_ARGS__); 

template<int Location, int Size> struct ReadOnlyBlock 
{ 
    static const unsigned int Data[Size]; 
    int loc() const { return Location; } 
    int size() const { return Size; } 
}; 

CreateReadOnlyBlock(readOnlyArray1, 0, 1, 2, 3); 
CreateReadOnlyBlock(readOnlyArray2, 4, 5, 6, 7); 
CreateReadOnlyBlock(readOnlyArray3, 9); 
CreateReadOnlyBlock(readOnlyArray4, 1, 2, 3, 4, 5); 

int main() 
{ 
    std::cout << "@" << readOnlyArray1.loc() << ": " << readOnlyArray1.size() << '\n'; 
    std::cout << "@" << readOnlyArray2.loc() << ": " << readOnlyArray2.size() << '\n'; 
    std::cout << "@" << readOnlyArray3.loc() << ": " << readOnlyArray3.size() << '\n'; 
    std::cout << "@" << readOnlyArray4.loc() << ": " << readOnlyArray4.size() << '\n'; 
} 

On ideone this prints:

@0: 4 
@4: 4 
@8: 1 
@9: 5 
+0

К сожалению, массивы имеют размер как 1k слов, но мне очень нравится это решение. Я должен был прояснить это, извините. Я редактировал свой пост. –

Смежные вопросы