I use the same “trick” of having a high level language as the macro language for an assembler. In my case I use Ada rather than C++. One of the useful features is a register allocator so I can simply ask for a currently unused register which gets allocated from a free register pool. Registers are then identified not by simple Ids but by Ada variables having meaningful names (i.e. names that are meaningful to the program being written). Registers allocated by this mechanism are then released to the free pool when they are no longer needed.
You wouldn’t want quite that with the belt, but I can envisage a similar mechanism where belt references are via C++ objects which automatically track their belt number.