фатальная ошибка c ++ C1061 с большим переключателем, метапрограммирование - PullRequest
2 голосов
/ 24 октября 2010

это код:

static inline void 
shrinkData(const vector<Data> &data, unsigned short shrinkType){
    #define CASE_N(N) \
    case(N): \
        ptr = MemoryManager::requestMemory(n*sizeof(ShrinkData<N>)); \
        for(int i=0; i<n; i++){ \
            new(ptr) ShrinkData<N>(data[i]); \
            ptr+=sizeof(ShrinkData<N>); \
        } \
        return;


    int n = data.size();
    char* ptr;

    switch(shrinkType){
    case(0):
        return;
    CASE_N(1)
    CASE_N(2)
    CASE_N(3)
    ....
    CASE_N(255)
}

теперь я получаю фатальную «ошибку C1061: ограничение компилятора: блоки вложены слишком глубоко» в строке CASE_N (124)

Может кто-нибудь сказать мне, почему это происходит? на самом деле вложение не должно быть глубже 2, нет?

Спасибо!

// edit: запрошенный конструктор (конструктор работает без этой функции переключателя)

enum {//maximally 16 to fit in a unsigned short!
    EID_POSITION        =   1, //bit1
    EID_T               =   2, //bit2
    EID_GEOMNORMAL      =   4, //bit3
    EID_NORMAL          =   8, //bit4
    EID_TANGENTS        =  16, //bit5
    EID_TEXCOORDS       =  32, //bit6
    EID_RAYDIR          =  64, //bit7
    EID_RECURSIONDEPTH  = 128  //bit8
};



template<unsigned, unsigned>
struct IDataMember{
    IDataMember(){}
    IDataMember(const Data &iData){}
};


template<>
struct IDataMember<EID_POSITION, EID_POSITION>{
    IDataMember(): position(Vector3(0,0,0)){}
    IDataMember(const Data &iData):position(iData.position){}
    Vector3 position;
};

... одинаковая специализация шаблонов для каждого типа в перечислениях ...

template<unsigned members>
struct ShrinkData
    :public IDataMember<members & EID_POSITION, EID_POSITION>
    ,public IDataMember<members & EID_T, EID_T>
    ,public IDataMember<members & EID_GEOMNORMAL, EID_GEOMNORMAL>
    ,public IDataMember<members & EID_NORMAL, EID_NORMAL>
    ,public IDataMember<members & EID_TANGENTS, EID_TANGENTS>
    ,public IDataMember<members & EID_TEXCOORDS, EID_TEXCOORDS>
    ,public IDataMember<members & EID_RAYDIR, EID_RAYDIR>
    ,public IDataMember<members & EID_RECURSIONDEPTH, EID_RECURSIONDEPTH>
{
    ShrinkData()
        :IDataMember<members & EID_POSITION, EID_POSITION>()
        ,IDataMember<members & EID_T, EID_T>()
        ,IDataMember<members & EID_GEOMNORMAL, EID_GEOMNORMAL>()
        ,IDataMember<members & EID_NORMAL, EID_NORMAL>()
        ,IDataMember<members & EID_TANGENTS, EID_TANGENTS>()
        ,IDataMember<members & EID_TEXCOORDS, EID_TEXCOORDS>()
        ,IDataMember<members & EID_RAYDIR, EID_RAYDIR>()
        ,IDataMember<members & EID_RECURSIONDEPTH, EID_RECURSIONDEPTH>(){}


    ShrinkData(const Data &iData)
        :IDataMember<members & EID_POSITION, EID_POSITION>(iData)
        ,IDataMember<members & EID_T, EID_T>(iData)
        ,IDataMember<members & EID_GEOMNORMAL, EID_GEOMNORMAL>(iData)
        ,IDataMember<members & EID_NORMAL, EID_NORMAL>(iData)
        ,IDataMember<members & EID_TANGENTS, EID_TANGENTS>(iData)
        ,IDataMember<members & EID_TEXCOORDS, EID_TEXCOORDS>(iData)
        ,IDataMember<members & EID_RAYDIR, EID_RAYDIR>(iData)
        ,IDataMember<members & EID_RECURSIONDEPTH, EID_RECURSIONDEPTH>(iData){}

};

Ответы [ 4 ]

2 голосов
/ 24 октября 2010

Я полагаю, что сообщение об ошибке является поддельным.Вероятно, действительно существует ограничение компилятора, но вряд ли это вложение блоков.

В любом случае, что произойдет, если вы поместите этот код для каждого case в собственный шаблон функции и просто вызовете его?
Кроме того, включение этой функции, скорее всего, ничего не даст вам, поскольку она будет запрашиватьпамять и выполнить цикл.Затраты на вызов функции должны быть пренебрежимо малы по сравнению с этим.(Независимо от того, как мало итераций занимает этот цикл, простая его настройка, вероятно, вдвое дешевле, чем вызов функции.)
Наконец, я бы на всякий случай попытался избавиться от макроса.

Код может выглядеть следующим образом:

// Beware, brain-compiled code ahead!
template<unsigned short N>
void do_it(int n)
{
  char* ptr = MemoryManager::requestMemory(n*sizeof(ShrinkData<N>));
  for(int i=0; i<n; i++){
    new(ptr) ShrinkData<N>(data[i]);
    ptr+=sizeof(ShrinkData<N>);
  }
}

static void 
shrinkData(const vector<Data> &data, unsigned short shrinkType)
{
  const std::vector<Data>::size_type n = data.size();
  switch(shrinkType){
    case   0: break
    case   1: do_it<  1>(n); break;
    case   2: do_it<  2>(n); break;
    .
    .
    .
    case 254: do_it<254>(n); break;
    case 255: do_it<255>(n); break;
}
2 голосов
/ 24 октября 2010

Согласно этой ссылке в компиляторе есть «функция», которая допускает только ограниченное количество циклов. Никогда со мной не бывало. Попробуйте поместить инициализацию ptr и следующий цикл for в блок. Другое решение состоит в том, чтобы создать шаблонную функцию, которая покрывает весь фрагмент кода, так что макрос становится примерно таким:

#define CASE_N(N) \
case(N): \
    ptr = requestAndInitialize<N>(data); \
    return;
0 голосов
/ 24 мая 2013

Я только что натолкнулся на это в каком-то автоматически сгенерированном коде;для петель, а не переключатель, но та же проблема.Вместо того, чтобы помещать все циклы в их собственные блоки - делая код несколько уродливее в процессе - я, по-видимому, решил проблему, переместив объявление итератора за пределы циклов, стиль C.

Я подозреваю, что проблема можетпоявится снова, если мы добавим слишком много дополнительных циклов, так как я полагаю, что из-за нехватки места для хранения данных области действия, но в то же время это намного приятнее.

Редактировать: конечно, проблема снова возникла через 1,5 года,И добавление дополнительного уровня вложенности исправило это.Я думаю, что этот ответ был больше для меня, чем для кого-либо другого.

0 голосов
/ 24 октября 2010

Просто размышления, но функция помечена как встроенная, и она также использует шаблоны, возможно, это часть того, откуда происходит дополнительное вложение.

Однако, скорее всего, IMO, ограничение ресурсов, которое вы бьете, вероятно, на самом деле не так четко выражено, как «уровни вложенности», а скорее, что это наиболее частая причина попадания, таксообщение об ошибке относится к.

...