Quirks of 'alias foo this'

Sean Cavanaugh WorksOnMyMachine at gmail.com
Mon Apr 25 17:47:15 PDT 2011


So my research into making a nice friendly to use COM interface wrapper 
for D has had a few odd turns and I am wondering if there is an answer 
to making the implementation nicer.

I discovered the 'alias foo this' syntax to let structs nearly 
seamlessly impersonate a member variable.  This has turned out to solve 
most of my original need to wrap the functions, but it is imperfect.

The main problem with 'alias foo this' is that I am having is that I 
can't find a way to catch code reading the aliased variable, in cases of 
assignment or implicit conversion to foo type.  I can catch writes just 
fine with opAssign, but finding a way to overload the reads have me stumped.

I did some experiments with wraping the methods with some mixin 
templates, but using 'alias foo this' is about 100% more useful, 
intuitive and 99.9% less code to write :)


Examples (The fully ComPtr code is down further):


// initializes to null by default
ComPtr!(ID3D11Device) device;
ComPtr!(ID3D11Device) otherdevice;

// The 'device' argument to D3D11CreateDevice is implemented as
// 'out ID3D11Device', and uses the 'alias p this' feature to
// auto-magically write directly into device.p;  Ideally
// I could hook this and either call SafeRelease here or assert
// that the p variable is null before being written to.
// This also represents the a case that you can write to the
// struct without detecting it.
HRESULT rslt = D3D11CreateDevice(
	null,
	D3D11_DRIVER_TYPE.HARDWARE,
	null,
	0 | D3D11_CREATE_DEVICE.DEBUG,
	null,
	0,
	D3D11_SDK_VERSION,
	device,
	&featureLevel,
	null);


// post-blit case, works
otherdevice = device;	


// gives me a copy of 'p' due to 'alias p this'
ID3D11Device rawdevice = device;	


// assignment back the other direction is caught by opAssign
// this is also the code path used if there are multiple COM
// interfaces in the hierarchy (IUnknown->ID3D11Resource->ID3D11Texture)
// and post-blit isn't used because the types are different.
device = rawdevice;






My current version of ComPtr:



struct ComPtr(T)
{
public:
     static assert(is(T : std.c.windows.com.IUnknown) || is(T : 
win32.unknwn.IUnknown));
     T p;
     alias p this;

private:
     this(T inPtr)
     {
         p = inPtr;
     }

public:
     this(this)
     {
         if (p !is null)
         {
             p.AddRef();
         }
     }
     ~this()
     {
         SafeRelease();
     }

     // Attach and Detach set/unset the pointer without messing with the 
refcount (unlike opAssign assignment)
     void Attach(T other)
     {
         SafeRelease();
         p = other;
     }
     T Detach()
     {
         T rval = p;
         p = null;
         return rval;
     }

     const bool HasData()
     {
         return (p !is null);
     }

     void opAssign(T other)
     {
         if (other !is null)
         {
             other.AddRef();
             SafeRelease();
             p = other;
         }
         else
         {
             SafeRelease();
         }
     }

     void SafeRelease()
     {
         if (p !is null)
         {
             p.Release();
             p = null;
         }
     }
}



More information about the Digitalmars-d-learn mailing list