Thread overview
Need assistance translating this C++ template
Oct 27, 2014
John
Oct 27, 2014
Justin Whear
Oct 27, 2014
anonymous
Oct 27, 2014
John
October 27, 2014
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.
October 27, 2014
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)
October 27, 2014
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 ... */
     }
}
October 27, 2014
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.