在编译时生成模板参数

Generating Template Parameters at Compile Time

本文关键字:参数 编译      更新时间:2023-10-16

我创建了一个看起来像数组的类,但它不是在程序本身中保存数据,而是将来自文件的字节流式传输(以减少RAM影响)。现在我已经使所有这些工作,但是程序员必须使用以下方式定义类:

#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指令通过汇编器中的一个工具来创建只读文件。

所以这是我的问题:我如何消除"位置"answers"大小"变量?我讨厌程序员必须手动输入这些,并且更喜欢在编译时生成这些。所以程序员不需要输入:

//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预处理器也可以,如果它不使它比它已经是丑陋的。这可能吗?

编辑:

在ReadOnlyBlock类中有这样一个方法:

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

位置变量和ROM文件之间存在内在的相互依存关系,我无法想到如何打破。我确实对工具链也有完全的控制,但是,我需要一种方法来传递汇编工具如何构造文件,以及指示c++代码块在文件中的位置。

另一个编辑:

文件及其块可以相当大,多达1k个字,因此许多预处理器的魔力可能会崩溃。同时,感谢大家的帮助,到目前为止!

我仍然没有看到生成名称(#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__)> 
{};

也许抓住了一点,但是否有可能使用可变模板而不是va_args?就像

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

基本上,任何你需要'location'的地方,使用T1。在需要size的地方,使用sizeof(TV) + 1。没有合适的编译器来测试这个,但是也许可以考虑一下…

这可能有帮助。我写了一些数积木的东西可以在块声明之前添加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;
}

如果下列条件成立:

  • 你不要在其他地方使用__COUNTER__
  • 所有数组的最大长度为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';
}

在ideone上打印:

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