www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Need assistance translating this C++ template

reply "John" <sirjohnalot gmail.com> writes:
Howdy,

I stumbled across a tiny NES emulator written in C++ 
(http://bisqwit.iki.fi/jutut/kuvat/programming_examples/nesemu1/nesemu1.cc) 
that I feel compelled to make even tinier with some D magic. I am 
having trouble with a nested template in the code.

The C++ code:

// Bitfield utilities
template<unsigned bitno, unsigned nbits=1, typename T=u8>
struct RegBit
{
     T data;
     enum { mask = (1u << nbits) - 1u };
     template<typename T2>
     RegBit& operator=(T2 val)
     {
         data = (data & ~(mask << bitno)) | ((nbits > 1 ? val & 
mask : !!val) << bitno);
         return *this;
     }
     operator unsigned() const { return (data >> bitno) & mask; }
     RegBit& operator++ ()     { return *this = *this + 1; }
     unsigned operator++ (int) { unsigned r = *this; ++*this; 
return r; }
};

My D implementation thus far:

// To avoid type confusion...
alias u8 = uint_least8_t;
alias u32 = uint_least32_t;

template RegBit(uint bitno, uint nbits = 1, T = u8) {
     T data;
     enum { mask = (1u << nbits) - 1u }

     // FIXME: Nested template frustration here... HELP
     void opAssign(T2 val)
     {
         data = (data & ~(mask << bitno)) | ((nbits > 1 ? val & 
mask : !!val) << bitno);
         return *this;
     }

     auto opCall() { return (data >> bitno) & mask; }
     ref RegBit opUnary(string s)() if (s == "++") { return *this 
= *this + 1; }
     ref RegBit opUnary(string s)(int) if (s== "++") { uint r = 
*this; ++*this; return r; }
}

Any push in the right direction would be greatly appreciated. I'm 
just trying to get a D implementation up and running before I 
start making this smaller and more intuitive.
Oct 27 2014
next sibling parent Justin Whear <justin economicmodeling.com> writes:
On Mon, 27 Oct 2014 22:43:22 +0000, John wrote:

      void opAssign(T2 val)
Without looking at the rest of your code, looks like this line needs to be void opAssign(T2)(T2 val)
Oct 27 2014
prev sibling parent reply "anonymous" <anonymous example.com> writes:
On Monday, 27 October 2014 at 22:43:23 UTC, John wrote:
 The C++ code:

 // Bitfield utilities
 template<unsigned bitno, unsigned nbits=1, typename T=u8>
 struct RegBit
 {
[...]
     template<typename T2>
     RegBit& operator=(T2 val)
[...]
 };

 My D implementation thus far:
[...]
 template RegBit(uint bitno, uint nbits = 1, T = u8) {
You're missing the struct here. Add some (template) parameters to a struct, and it becomes a struct template: struct RegBit(uint bitno, uint nbits = 1, T = u8) [...]
     // FIXME: Nested template frustration here... HELP
     void opAssign(T2 val)
Similarly, add another set of (template) parameters to a function/method, before the runtime parameters, and it becomes a function/method template: void opAssign(T2)(T2 val) [...]
 }
Those "slap another set of parameters on, and it's a template" syntaxes, are sugar for the longer "eponymous member" variant: struct Foo(T) {} is equivalent to template Foo(T) { struct Foo /* same name as the template */ { /* ... */ } } Works with structs, classes, functions, etc. So if you wanted to spell the templates out, it would look like this: template RegBit(uint bitno, uint nbits = 1, T = u8) { struct RegBit { /* ... other members of RegBit ... */ template opAssign(T2) { void opAssign(T2 val) { /* ... implementation of opAssign ... */ } } /* ... other members of RegBit ... */ } }
Oct 27 2014
parent "John" <sirjohnalot gmail.com> writes:
On Monday, 27 October 2014 at 23:19:42 UTC, anonymous wrote:
 On Monday, 27 October 2014 at 22:43:23 UTC, John wrote:
 The C++ code:

 // Bitfield utilities
 template<unsigned bitno, unsigned nbits=1, typename T=u8>
 struct RegBit
 {
[...]
    template<typename T2>
    RegBit& operator=(T2 val)
[...]
 };

 My D implementation thus far:
[...]
 template RegBit(uint bitno, uint nbits = 1, T = u8) {
You're missing the struct here. Add some (template) parameters to a struct, and it becomes a struct template: struct RegBit(uint bitno, uint nbits = 1, T = u8) [...]
    // FIXME: Nested template frustration here... HELP
    void opAssign(T2 val)
Similarly, add another set of (template) parameters to a function/method, before the runtime parameters, and it becomes a function/method template: void opAssign(T2)(T2 val) [...]
 }
Those "slap another set of parameters on, and it's a template" syntaxes, are sugar for the longer "eponymous member" variant: struct Foo(T) {} is equivalent to template Foo(T) { struct Foo /* same name as the template */ { /* ... */ } } Works with structs, classes, functions, etc. So if you wanted to spell the templates out, it would look like this: template RegBit(uint bitno, uint nbits = 1, T = u8) { struct RegBit { /* ... other members of RegBit ... */ template opAssign(T2) { void opAssign(T2 val) { /* ... implementation of opAssign ... */ } } /* ... other members of RegBit ... */ } }
Much appreciated! I saw I didn't even make it a struct shortly after posting, time to take a nap and restrain the caffeine intake. And thanks for the missing parameter, Justin.
Oct 27 2014