Enumerators, Templates, and Type Safety

M

Matt Taylor

I'm trying to write an x86 assembler in C++ for use in a debugger. What I'd
like do is to use template specialization to prevent invalid combinations
from compiling. Thus one could not accidentally add a 16-bit register and an
8-bit register since there is no encoding for this on the x86 architecture.

My trouble has stemmed from the fact that enumerators are only integers and
can be freely cast into other enumerators, and I was using them to attempt
type safety. I declared REG8, REG16, and REG32 enumerated types, but the
compiler will implicitly cast between them. So, my question is: is there any
way to create 3 distinct types that I can use in template specialization to
enforce assembler operand restrictions at compile-time?

-Matt
 
V

Victor Bazarov

Matt said:
I'm trying to write an x86 assembler in C++ for use in a debugger. What I'd
like do is to use template specialization to prevent invalid combinations
from compiling. Thus one could not accidentally add a 16-bit register and an
8-bit register since there is no encoding for this on the x86 architecture.

My trouble has stemmed from the fact that enumerators are only integers and
can be freely cast into other enumerators, and I was using them to attempt
type safety. I declared REG8, REG16, and REG32 enumerated types, but the
compiler will implicitly cast between them. So, my question is: is there any
way to create 3 distinct types that I can use in template specialization to
enforce assembler operand restrictions at compile-time?

How about

class REG8 {} AL,AH,BL,BH,CL,CH,DL,DH;
class REG16 {} AX,BX,CX,DX,SI,DI,BP,SP,IP;
class REG32 {} EAX ...

Now you have types, you have objects. You can't easily use them
in a 'switch', but do you care? There is no conversion between
any of them, and you can specialise your templates based on them
as much as you can specialise any templates.

V
 
J

JKop

Victor Bazarov posted:
How about

class REG8 {} AL,AH,BL,BH,CL,CH,DL,DH;
class REG16 {} AX,BX,CX,DX,SI,DI,BP,SP,IP;
class REG32 {} EAX ...

Now you have types, you have objects. You can't easily use them
in a 'switch', but do you care? There is no conversion between
any of them, and you can specialise your templates based on them
as much as you can specialise any templates.

V

or maybe

namespace REG8 {
enum REG8 {

AL,AH,BL,BH,CL,CH,DL,DH }}

namespace REG16 {
enum REG16 {
AX,BX,CX,DX,SI,DI,BP,SP,IP }}


void Add(REG16 x, REG16 y);

void Add(REG8 x, REG8 y);


int main()
{
Add(REG16::BX,REG16::BP);

Add(REG8::BH,REG8::DH);

Add(REG16::BX,REG8::AL); //COMPILE ERROR
}


-JKop
 
J

JKop

JKop posted:
Victor Bazarov posted:


or maybe

namespace REG8 {
enum REG8 {

AL,AH,BL,BH,CL,CH,DL,DH }}

namespace REG16 {
enum REG16 {
AX,BX,CX,DX,SI,DI,BP,SP,IP }}


void Add(REG16 x, REG16 y);

void Add(REG8 x, REG8 y);

Opps!

void Add(REG16::REG16 x, REG16::REG16 y);

void Add(REG8::REG8 x, REG8::REG8 y);

-JKop
 
M

Matt Taylor

JKop said:
Victor Bazarov posted:


or maybe

namespace REG8 {
enum REG8 {

AL,AH,BL,BH,CL,CH,DL,DH }}

namespace REG16 {
enum REG16 {
AX,BX,CX,DX,SI,DI,BP,SP,IP }}


void Add(REG16 x, REG16 y);

void Add(REG8 x, REG8 y);


int main()
{
Add(REG16::BX,REG16::BP);

Add(REG8::BH,REG8::DH);

Add(REG16::BX,REG8::AL); //COMPILE ERROR
}

What about template specialization, e.g. Add<REG16::BX, REG8::AL>()? I
suppose I can live with passing parameters, but I'd hoped to use
specialization to force the compiler to inline everything.

-Matt
 
M

Matt Taylor

Victor Bazarov said:
How about

class REG8 {} AL,AH,BL,BH,CL,CH,DL,DH;
class REG16 {} AX,BX,CX,DX,SI,DI,BP,SP,IP;
class REG32 {} EAX ...

Now you have types, you have objects. You can't easily use them
in a 'switch', but do you care? There is no conversion between
any of them, and you can specialise your templates based on them
as much as you can specialise any templates.

This seems to work pretty well. I actually ended up creating a generic class
that represents each register type, i.e. REG8, REG16, and REG32. They are
templated with an integer, i.e. EAX = REG32<0>. Now I can use partial
specialization to easily select between register types. Thanks!

-Matt
 
V

Victor Bazarov

Matt said:
[..] I actually ended up creating a generic class
that represents each register type, i.e. REG8, REG16, and REG32. They are
templated with an integer, i.e. EAX = REG32<0>. Now I can use partial
specialization to easily select between register types. Thanks!

It's very gratifying to interact with somebody who understands what
you're talking about and uses it successfully. Thank you. -- V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,142
Latest member
arinsharma
Top