Alright. I’m explaining you the problem you’re facing. But first thing first. You said:
I wrote a template class which is
giving compilation error
First of all, as far as C++ is concerned, there is no such thing as a «template class,» there is only a «class template.» The way to read that phrase is «a template for a class,» as opposed to a «function template,» which is «a template for a function.» Again: classes do not define templates, templates define classes (and functions).* Quoted from here.
Now, lets see the error:
fatal error C1202: recursive type or
function dependency context too
complex
The error says it all. $14.7.1 from the Standard explains the cause of your problem very well, giving you even an example which is very much close to what you’re doing. So I don’t even need to write a single word of my own. Here is $14.7.1
4 There is an implementation-defined
quantity that specifies the limit on
the total depth of recursive
instantiations, which
could involve more than one template. The result of an infinite
recursion in instantiation is
undefined. [ Example:template < class T > class X { X<T >* p; // OK X<T*> a; //implicit generation of X<T> requires //the implicit instantiation of X<T*> which requires //the implicit instantiation of X<T**> which ... };—end example ]
Please read the comment with X<T*> a, which is pretty much the case with you too. So your problem is not because of recursive function, it’s rather because of recursive instantiation of class template, causing from these lines:
Entity<T*> pPrev;
Entity<T*> pNext;
Hope, it solves your problem!
EDIT : But I’m wondering what are you trying to achieve with Entity<T*> pPrev? It seems its a typo, and you probably wanted to write Entity<T>* pPrev. Same with pNext. Is that so?
And an advice to improve the design : Use Member Initialization list, instead of Assignment. That is, write your constructor the following way,
Entity<T>(const string & name, int size) : EntityName(name), EntitySize(size)
{
//all assignments moved to initialization list.
}
Read this : Why should I prefer to use member initialization list?
I’m doing some templatized recursion for an arbitrary NxN matrix: (summarizing)
template<class type, int N>
class MatrixNxN
{
// component-wise copy
template<int N>
static void copy(type* out, const type* u){
*out = *u; copy<N-1>(out+1, u+1);}
template<>
static void copy<1>(type* out, const type* u){
*out = *u;}
..
};
So, I need to create a 64×64 matrix by MatrixNxN<float,64*64>, but I get the error: fatal error C1202: recursive type or function dependency context too complex.
I’m using Visual Studio.NET 2003. Does someone know if I can turn this off, or get around it in some way (other than doing the recursion at run-time)? Is there an option I didn’t find in project settings or something?
Thanks
Recursion depth is a setting of most compilers, often it limited to a depth of 20.
Cheers
Chris
CheersChris
Yeah, I fully understand the problem. My question is how do I get around it and still get the compile-time optimization.
Any Ideas?
How about unrolling the copy function? So, for example, handle four iterations simultaneously and specialize for sizes 1 to 4.
Also, wouldn’t it be a lot safe just to write a loop and let the compiler unroll it for you? This seems like a nasty template hack anyway, I bet it’s going to create some interesting 4-page identifiers 
Your main performance consern should be to inform the compiler of any aliasing restrictions anyway..
[Edited by — doynax on February 12, 2005 1:02:45 AM]
If the loop needs unrolling, the compiler will unroll it for you. Under certain circumstances, this manual unrolling will slow things down. Don’t do this sort of thing.
Quote:Original post by Sneftel
If the loop needs unrolling, the compiler will unroll it for you. Under certain circumstances, this manual unrolling will slow things down. Don’t do this sort of thing.
Quoted for emphisis. I would be extremely suprized if this method worked better in ANY circumstance.
Also, your class or arguments are very poorly named. MatrixNxN implies that the matrix is N x N in size, whereas providing N=64*64 is used in your example supposedly creates a 64×64 matrix instead of a 4096×4096.
Further, this code is at best very innefficent for a copy. You’ll suffer an extreme performance hit in debug mode, because for every copy you’ll be passing two arguments and calling. Plus, your codepage and EXE size will jump as the maximum size of your array does. In the best case scenario during release mode (which is nearly guaranteed not to happen is my 2 cents) it’ll have the same effect as the correct unrolling of your loop, which your compiler knows more than you about and will do for you. In the worse case scenario it’ll be just as bad as debug mode.
Furhter, a generic copy function does not belong in a matrix class. To implement your own you’d want to write it as a normal function. However, you may want to use std::copy or std::copy_n, both of which were written by people who know more about this than you do. No offense, it’s just that they’re professionals, and there’s no sense in reinventing the wheel.
Thanks for all your help.
At the risk of sounding defensive, I’m actually doing this as part of a school project, so the point is to gain first hand knowledge about the advantages and disadvantages. I guess maximum size goes under the disadvantage column.
Я пытаюсь создать интерпретатор PPU через встроенные массивы opcode для выполнения обработчика для интерпретации инструкции. Инструкция может быть одной из нескольких форм (I-Form, B-Form, D-Form, X-Form и т.д.), Но у меня небольшая проблема с X-Form для основного кода операции 31. Я использую класс шаблона InterpretArray, который автоматически назначает обработчики в массиве. Этот класс также может использоваться как вспомогательный массив обработчиков, который может быть вызван из обработчика. Компилятор VS2013 дает мне эту фатальную ошибку:
1> main.cpp(196): фатальная ошибка C1202: контекст зависимости рекурсивного типа или функции слишком сложный
template < size_t xo_rc >
struct Interpreter < X_Form_31_XORc < xo_rc > >
Похоже, компилятор не любит X_Form_31_XORc, любая идея почему? как я могу избежать этого?
Здесь источник, который может быть скомпилирован отлично, если X_FORM не определено:
#include <iostream>
#define B_FORM
//#define X_FORM
using namespace std;
// Dummy stuff
typedef unsigned int u32;
typedef signed int s32;
union Instruction
{
#define FIELD(from, to, type) struct{ u32:(32-to-1); type:(to-from+1); u32:from; }
u32 instruction;
// Opcode fields
FIELD(0, 5, u32 opcode); // Primary opcode
FIELD(26, 31, u32 op4); // Extended opcode of 6-bits (up to 0x3F)
FIELD(21, 31, u32 op4_); // Extended opcode of 11-bits (up to 0x7FF)
FIELD(21, 30, u32 op19); // Extended opcode of 10-bits (up to 0x3FF)
FIELD(27, 29, u32 op30); // Extended opcode of 3-bits (up to 0x7)
FIELD(21, 30, u32 op31); // Extended opcode of 10-bits (up to 0x3FF)
FIELD(30, 31, u32 op58); // Extended opcode of 2-bits (up to 0x3)
FIELD(26, 30, u32 op59); // Extended opcode of 5-bits (up to 0x1F)
FIELD(30, 31, u32 op62); // Extended opcode of 2-bits (up to 0x3)
FIELD(26, 30, u32 op63); // Extended opcode of 5-bits (up to 0x1F)
FIELD(21, 30, u32 op63_); // Extended opcode of 10-bits (up to 0x3FF)
// Instruction fields
FIELD(30, 30, u32 aa); // Bit/Flags: Absolute address bit
FIELD(31, 31, u32 lk); // Bit/Flags: Link bit: Update the link register (LR)
FIELD(21, 21, u32 oe); // Bit/Flags: OE bit: Enable enable setting OV and SO in the XER
FIELD(31, 31, u32 rc); // Bit/Flags: Record bit: Update the condition register (CR)
FIELD(6, 6, u32 l6); // Bit/Flags: ?
FIELD(10, 10, u32 l10); // Bit/Flags: ?
FIELD(11, 11, u32 l11); // Bit/Flags: ?
FIELD(9, 10, u32 l9_10); // Bit/Flags: ?
FIELD(6, 10, u32 bo); // Branching: Options for the branch conditional instructions
FIELD(11, 15, u32 bi); // Branching: CR bit to trigger branch conditional instructions
FIELD(16, 29, s32 bd); // Branching: Immediate 14-bit signed integer for branch displacement
FIELD(19, 20, u32 bh); // ?
FIELD(11, 13, u32 bfa); // ?
FIELD(6, 8, u32 crfd); // CR fields: Destination CR or FPSCR field
FIELD(11, 13, u32 crfs); // CR fields: Source CR or FPSCR field
FIELD(6, 10, u32 crbd); // CR fields: Destination bit in the CR or FPSCR
FIELD(11, 15, u32 crba); // CR fields: Source bit in the CR
FIELD(16, 20, u32 crbb); // CR fields: Source bit in the CR
FIELD(12, 19, u32 crm); // Identify the CR fields that are to be updated by the mtcrf instruction
FIELD(16, 31, s32 d); // Immediate 16-bit signed integer
FIELD(16, 27, u32 dq); // ?
FIELD(16, 29, s32 ds); // ?
FIELD(7, 14, u32 fm); // ?
FIELD(6, 10, u32 frd); // FPR: Destination
FIELD(6, 10, u32 frs); // FPR: Source
FIELD(11, 15, u32 fra); // FPR: Source
FIELD(16, 20, u32 frb); // FPR: Source
FIELD(21, 25, u32 frc); // FPR: Source
FIELD(16, 19, u32 imm); // Immediate for to place in FPSCR
FIELD(6, 29, s32 li); // Branching:
FIELD(6, 29, s32 ll); // Branching:
FIELD(21, 25, u32 mb); // First '1' bit of a 64-bit mask in rotate instructions
FIELD(26, 26, u32 mb_); // First '1' bit of a 64-bit mask in rotate instructions: Split field
FIELD(26, 30, u32 me); // Last '1' bit of a 64-bit mask in rotate instructions
FIELD(21, 25, u32 me_); // Last '1' bit of a 64-bit mask in rotate instructions: Split field
FIELD(26, 26, u32 me__); // Last '1' bit of a 64-bit mask in rotate instructions: Split field
FIELD(16, 20, u32 nb); // Number of bytes to move in an immediate string load or store
FIELD(6, 10, u32 rd); // GPR: Destination
FIELD(6, 10, u32 rs); // GPR: Source
FIELD(11, 15, u32 ra); // GPR: Source
FIELD(16, 20, u32 rb); // GPR: Source
FIELD(16, 20, u32 sh); // Shift amount
FIELD(30, 30, u32 sh_); // Shift amount: Split field
FIELD(11, 20, u32 spr); // Special-purpose register
FIELD(9, 10, u32 strm); // ?
FIELD(20, 26, u32 lev); // ?
FIELD(16, 31, s32 simm); // Immediate 16-bit signed integer
FIELD(16, 31, u32 uimm); // Immediate 16-bit unsigned integer
FIELD(9, 10, u32 th); // Data stream variant of the dcbt instruction
FIELD(6, 10, u32 to); // Trap conditions
FIELD(6, 10, u32 vd); // Vector/SIMD: Destination vector register
FIELD(6, 10, u32 vs); // Vector/SIMD: Source vector register
FIELD(11, 15, u32 va); // Vector/SIMD: Source vector register
FIELD(16, 20, u32 vb); // Vector/SIMD: Source vector register
FIELD(21, 25, u32 vc); // Vector/SIMD: Source vector register
FIELD(22, 25, u32 vshb); // Vector/SIMD: Specifies a shift amount in bytes
FIELD(11, 15, s32 vsimm); // Vector/SIMD: Immediate 5-bit signed integer
FIELD(11, 15, u32 vuimm); // Vector/SIMD: Immediate 5-bit unsigned integer
#undef FIELD
};
struct PPUThread {}; // register context but we do not need it here
// Opcode part
// auto-initialize by recursively assigning all handlers in an opcode array
template< template< typename > class Handler,
template< size_t > class Indexer,
size_t start_index,
size_t end_index >
struct OpcodeArrayRange
{
template< typename Owner >
static __forceinline void initialize(Owner & owner)
{
owner.array[start_index] = Handler< Indexer< start_index > >::handle;
OpcodeArrayRange< Handler, Indexer, start_index + 1, end_index >::initialize(owner);
}
};
// auto-initialize by assigning the last handler in an opcode array
template< template< typename > class Handler,
template< size_t > class Indexer,
size_t start_index >
struct OpcodeArrayRange < Handler, Indexer, start_index, start_index >
{
template< typename Owner >
static __forceinline void initialize(Owner & owner)
{
owner.array[start_index] = Handler< Indexer< start_index > >::handle;
}
};
template < size_t po >
struct OPCD // Primary opcode, used for Indexer in OpcodeArrayRange
{
};
#ifdef B_FORM
template < size_t po >
using B_Form = OPCD < po >;
template < size_t bo_bi >
struct B_Form_BOBI
{
};
#endif
#ifdef X_FORM
template < size_t po >
using X_Form = OPCD < po > ; // Primary opcode + Extended opcode + Record bit
template < size_t po, size_t xo, size_t rc >
struct X_Form_XO_Rc // Primary opcode + Extended opcode + Record bit
{
};
template < size_t po, size_t xo_rc >
struct X_Form_XORc // glue Extended opcode and Record bit into one field, used for Indexer in OpcodeArrayRange
{
};
template < size_t xo_rc >
using X_Form_31_XORc = X_Form_XORc < 31, xo_rc > ; // alias to X_Form_XORc with Primary opcode 31
#endif
// Interpreter part
template< typename T >
struct Interpreter
{
};
// generic interpreter array
template< template< size_t > class OpcodeFormat,
size_t start_index,
size_t end_index >
struct InterpretArray :
OpcodeArrayRange < Interpreter, OpcodeFormat, start_index, end_index >
{
InterpretArray()
{
initialize(*this);
}
__forceinline void operator()(size_t index,
Instruction code,
PPUThread& thread)
{
array[index](code, thread);
}
void(*array[1 + end_index - start_index])(Instruction, PPUThread&);
};
// implementation for interpreting opcodes
template< size_t po >
struct Interpreter < OPCD < po > >
{
static void handle(Instruction /*code*/, PPUThread& /*thread*/)
{
std::cout
<< "OPCD #"
<< po
<< std::endl;
}
};
#ifdef B_FORM
template < size_t bo_bi >
struct Interpreter < B_Form_BOBI < bo_bi > >
{
static void handle(Instruction code, PPUThread& thread)
{
std::cout
<< "OPCD #31, BO #"
<< (bo_bi >> 5)
<< ", BI #"
<< (bo_bi & 31)
<< ", AA #"
<< (code.aa)
<< ", LK #"
<< (code.lk)
<< std::endl;
}
};
static InterpretArray < B_Form_BOBI, 0, 0x3FF > interpret_B_Form_BOBI;
template< >
struct Interpreter < B_Form < 16 > >
{
static void handle(Instruction code, PPUThread& thread)
{
interpret_B_Form_BOBI((code.instruction >> 16) & 0x3FF, code, thread);
}
};
#endif
#ifdef X_FORM
template < size_t xo_rc >
struct Interpreter < X_Form_31_XORc < xo_rc > >
{
static void handle(Instruction /*code*/, PPUThread& /*thread*/)
{
std::cout
<< "OPCD #31, XO #"
<< (xo_rc >> 1)
<< ", Rc #"
<< (xo_rc & 1)
<< std::endl;
}
};
// specific interpreter array for instructions selected by their extended code
// and Record bit when primary opcode is 31
static InterpretArray < X_Form_31_XORc, 0, 0x7FF > interpret_X_Form_31;
template< >
struct Interpreter < X_Form < 31 > > // note that X_Form is an alias to OPCD
{
static void handle(Instruction code, PPUThread& thread)
{
interpret_X_Form_31((code.instruction & 0x7FF), code, thread);
}
};
#endif
// specific interpreter array for instructions
// selected by primary opcode
static InterpretArray < OPCD, 0, 0x3F > interpret;
int main()
{
Instruction insn;
PPUThread thread;
{
insn.opcode = 2;
interpret(insn.opcode, insn, thread);
}
#ifdef B_FORM
{
insn.opcode = 16;
insn.bo = 2;
insn.bi = 3;
insn.aa = 1;
insn.lk = 1;
interpret(insn.opcode, insn, thread);
}
#endif
#ifdef X_FORM
{
insn.opcode = 31;
insn.op31 = 2;
insn.rc = 0;
interpret(insn.opcode, insn, thread);
}
{
insn.opcode = 31;
insn.op31 = 2;
insn.rc = 1;
interpret(insn.opcode, insn, thread);
}
#endif
}
EDIT: я добавил B_Form, который похож на X_Form, но не использует псевдоним, и он работает (но строительство довольно медленное).
