Thread overview
Mimicking IID_PPV_ARGS
Aug 29, 2018
Cody Duncan
Aug 30, 2018
Cody Duncan
August 29, 2018
From C++
#define IID_PPV_ARGS(ppType) __uuidof(**(ppType)), IID_PPV_ARGS_Helper(ppType)

//ComPtr version
ComPtr<ID3D12Debug> debugController;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
{
	// do stuff
}

//Raw Pointer Version
ID3D12Debug* debugController;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
{
	// do stuff
}

IID_PPV_ARGS expands into two arguments of types (const IID &, void**).

The first arg expansion uses a compiler intrinsic to look up the GUID of the type.

The second arg expansion uses an IID_PPV_ARGS_Helper, a templated function that return a void**. This either forwards the address of the pointer passed in,
or the result of  ReleaseAndGetAddressOf() from the com object within the ComPtr.



Now in D!
Here is my attempt so far, pared down to just enough to compile "IID_PPV_ARGS(debugController).expand".

// ----- uuidtemplate.d -----
module uuidtemplate;
import core.sys.windows.com;

mixin( uuid!(IUnknown, "00000000-0000-0000-C000-000000000046"));
mixin( uuid!(IClassFactory,"00000001-0000-0000-C000-000000000046"));

template uuid(T, const char[] g) {
	const char [] uuid =
		"const IID IID_"~T.stringof~"={ 0x" ~ g[0..8] ~ ",0x" ~ g[9..13] ~ ",0x" ~ g[14..18] ~ ",[0x" ~ g[19..21] ~ ",0x" ~ g[21..23] ~ ",0x" ~ g[24..26] ~ ",0x" ~ g[26..28] ~ ",0x" ~ g[28..30] ~ ",0x" ~ g[30..32] ~ ",0x" ~ g[32..34] ~ ",0x" ~ g[34..36] ~ "]};"~
		"template uuidof(T:"~T.stringof~"){"~
		"	const IID uuidof ={ 0x" ~ g[0..8] ~ ",0x" ~ g[9..13] ~ ",0x" ~ g[14..18] ~ ",[0x" ~ g[19..21] ~ ",0x" ~ g[21..23] ~ ",0x" ~ g[24..26] ~ ",0x" ~ g[26..28] ~ ",0x" ~ g[28..30] ~ ",0x" ~ g[30..32] ~ ",0x" ~ g[32..34] ~ ",0x" ~ g[34..36] ~ "]};"~
		"}";
}

//  ----- debuginterface.d -----
module debuginterface;

import core.sys.windows.com;
import uuidtemplate : uuid; // uuidof

mixin(uuid!(ID3D12Debug, "344488b7-6846-474b-b989-f027448245e0"));
interface ID3D12Debug : IUnknown {
	void EnableDebugLayer();
}

//  ----- comptr.d -----
module comptr;
public import std.typecons;
import core.sys.windows.com;
import uuidtemplate : uuid; // uuidof

mixin template IID_PPV_ARGS()
{
	auto IID_PPV_ARGS(T : ComPtr!U, U)(ref T arg)
	{
		return tuple(&uuidof!(U), arg.ptrRef());
	}

	auto IID_PPV_ARGS(T)(ref T arg)
	{
		return tuple(&uuidof!(T), &arg);
	}
}

template ComPtr(T)
{
	struct ComPtr
	{
	protected:
		T _ptr = null;

	public:
		this(ref T inVar)
		{
			_ptr = inVar;
		}

		@property T ptr() { return _ptr; }
		@property T* ptrRef() { return &_ptr; }
		
		alias ptr this;
	}
}


//  ----- app.d -----
module app;

import core.sys.windows.com;
import comptr;
import debuginterface;
import std.stdio;

// Necessary to mixin since the declaration in comptr.d
// cannot see the uuidof declared by debuginterface.
// When removing the mixin, it always returns the GUID for IUnknown.
mixin IID_PPV_ARGS;

bool D3D12GetDebugInterface(const (GUID)* riid, ID3D12Debug* ppvDebug)
{
	printf("Guid = {%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}",
	riid.Data1, riid.Data2, riid.Data3,
	riid.Data4[0], riid.Data4[1], riid.Data4[2], riid.Data4[3],
	riid.Data4[4], riid.Data4[5], riid.Data4[6], riid.Data4[7]);

	// output should be: "344488b7-6846-474b-b989-f027448245e0"

	return true;
}

void main()
{
	ComPtr!ID3D12Debug debugController;

	// I want to get rid of the .expand syntax here
	if (D3D12GetDebugInterface(IID_PPV_ARGS(debugController).expand))
	{
		writefln("success!");
	}
}

/// end code

So my goal here is to get the syntax for IID_PPV_ARGS down to looking just like a function call.

I'd like to get rid of the .expand call. I haven't figured out a better way to express converting the ComPtr input into two outputs used as separate arguments into the outer function.

Any ideas?
August 29, 2018
On 8/29/18 5:51 AM, Cody Duncan wrote:
>  From C++
> #define IID_PPV_ARGS(ppType) __uuidof(**(ppType)), IID_PPV_ARGS_Helper(ppType)
> 
> //ComPtr version
> ComPtr<ID3D12Debug> debugController;
> if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
> {
>      // do stuff
> }
> 
> //Raw Pointer Version
> ID3D12Debug* debugController;
> if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
> {
>      // do stuff
> }
> 
> IID_PPV_ARGS expands into two arguments of types (const IID &, void**).
> 
> The first arg expansion uses a compiler intrinsic to look up the GUID of the type.
> 
> The second arg expansion uses an IID_PPV_ARGS_Helper, a templated function that return a void**. This either forwards the address of the pointer passed in,
> or the result of  ReleaseAndGetAddressOf() from the com object within the ComPtr.
> 
> 
> 
> Now in D!
> Here is my attempt so far, pared down to just enough to compile "IID_PPV_ARGS(debugController).expand".
> 
> // ----- uuidtemplate.d -----
> module uuidtemplate;
> import core.sys.windows.com;
> 
> mixin( uuid!(IUnknown, "00000000-0000-0000-C000-000000000046"));
> mixin( uuid!(IClassFactory,"00000001-0000-0000-C000-000000000046"));
> 
> template uuid(T, const char[] g) {
>      const char [] uuid =
>          "const IID IID_"~T.stringof~"={ 0x" ~ g[0..8] ~ ",0x" ~ g[9..13] ~ ",0x" ~ g[14..18] ~ ",[0x" ~ g[19..21] ~ ",0x" ~ g[21..23] ~ ",0x" ~ g[24..26] ~ ",0x" ~ g[26..28] ~ ",0x" ~ g[28..30] ~ ",0x" ~ g[30..32] ~ ",0x" ~ g[32..34] ~ ",0x" ~ g[34..36] ~ "]};"~
>          "template uuidof(T:"~T.stringof~"){"~
>          "    const IID uuidof ={ 0x" ~ g[0..8] ~ ",0x" ~ g[9..13] ~ ",0x" ~ g[14..18] ~ ",[0x" ~ g[19..21] ~ ",0x" ~ g[21..23] ~ ",0x" ~ g[24..26] ~ ",0x" ~ g[26..28] ~ ",0x" ~ g[28..30] ~ ",0x" ~ g[30..32] ~ ",0x" ~ g[32..34] ~ ",0x" ~ g[34..36] ~ "]};"~
>          "}";
> }
> 
> //  ----- debuginterface.d -----
> module debuginterface;
> 
> import core.sys.windows.com;
> import uuidtemplate : uuid; // uuidof
> 
> mixin(uuid!(ID3D12Debug, "344488b7-6846-474b-b989-f027448245e0"));
> interface ID3D12Debug : IUnknown {
>      void EnableDebugLayer();
> }
> 
> //  ----- comptr.d -----
> module comptr;
> public import std.typecons;
> import core.sys.windows.com;
> import uuidtemplate : uuid; // uuidof
> 
> mixin template IID_PPV_ARGS()
> {
>      auto IID_PPV_ARGS(T : ComPtr!U, U)(ref T arg)
>      {
>          return tuple(&uuidof!(U), arg.ptrRef());
>      }
> 
>      auto IID_PPV_ARGS(T)(ref T arg)
>      {
>          return tuple(&uuidof!(T), &arg);
>      }
> }
> 
> template ComPtr(T)
> {
>      struct ComPtr
>      {
>      protected:
>          T _ptr = null;
> 
>      public:
>          this(ref T inVar)
>          {
>              _ptr = inVar;
>          }
> 
>          @property T ptr() { return _ptr; }
>          @property T* ptrRef() { return &_ptr; }
> 
>          alias ptr this;
>      }
> }
> 
> 
> //  ----- app.d -----
> module app;
> 
> import core.sys.windows.com;
> import comptr;
> import debuginterface;
> import std.stdio;
> 
> // Necessary to mixin since the declaration in comptr.d
> // cannot see the uuidof declared by debuginterface.
> // When removing the mixin, it always returns the GUID for IUnknown.
> mixin IID_PPV_ARGS;
> 
> bool D3D12GetDebugInterface(const (GUID)* riid, ID3D12Debug* ppvDebug)
> {
>      printf("Guid = {%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}",
>      riid.Data1, riid.Data2, riid.Data3,
>      riid.Data4[0], riid.Data4[1], riid.Data4[2], riid.Data4[3],
>      riid.Data4[4], riid.Data4[5], riid.Data4[6], riid.Data4[7]);
> 
>      // output should be: "344488b7-6846-474b-b989-f027448245e0"
> 
>      return true;
> }
> 
> void main()
> {
>      ComPtr!ID3D12Debug debugController;
> 
>      // I want to get rid of the .expand syntax here
>      if (D3D12GetDebugInterface(IID_PPV_ARGS(debugController).expand))
>      {
>          writefln("success!");
>      }
> }
> 
> /// end code
> 
> So my goal here is to get the syntax for IID_PPV_ARGS down to looking just like a function call.
> 
> I'd like to get rid of the .expand call. I haven't figured out a better way to express converting the ComPtr input into two outputs used as separate arguments into the outer function.
> 
> Any ideas?

Unfortunately, D does not allow you to return an alias sequence directly. So you have to return a struct, which is going to be utilized instead of the alias this'd alias sequence inside the tuple. This is why it's necessary for the expand call.

However, it's not much different to accept the struct than it is to accept the 2 items in the struct. Why not just modify the function D3D12... to accept a struct instead of the 2 parameters? You could even overload it, if you still want to call it directly:

bool D3D12GetDebugInterface(Tuple!(const (GUID)*, ID3D12Debug*) param)
{
   return D3D12GetDebugInterface(param.expand);
}

My preference would be to encompass all the logic for pairing the 2 items together into a specialized struct, not a tuple.

-Steve
August 30, 2018
On Wednesday, 29 August 2018 at 16:17:13 UTC, Steven Schveighoffer wrote:
> On 8/29/18 5:51 AM, Cody Duncan wrote:
>>  From C++
>> #define IID_PPV_ARGS(ppType) __uuidof(**(ppType)), IID_PPV_ARGS_Helper(ppType)
>> 
>> //ComPtr version
>> ComPtr<ID3D12Debug> debugController;
>> if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
>> {
>>      // do stuff
>> }
>> 
>> //Raw Pointer Version
>> ID3D12Debug* debugController;
>> if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
>> {
>>      // do stuff
>> }
>> 
>> IID_PPV_ARGS expands into two arguments of types (const IID &, void**).
>> 
>> The first arg expansion uses a compiler intrinsic to look up the GUID of the type.
>> 
>> The second arg expansion uses an IID_PPV_ARGS_Helper, a templated function that return a void**. This either forwards the address of the pointer passed in,
>> or the result of  ReleaseAndGetAddressOf() from the com object within the ComPtr.
>> 
>> 
>> 
>> Now in D!
>> Here is my attempt so far, pared down to just enough to compile "IID_PPV_ARGS(debugController).expand".
>> 
>> // ----- uuidtemplate.d -----
>> module uuidtemplate;
>> import core.sys.windows.com;
>> 
>> mixin( uuid!(IUnknown, "00000000-0000-0000-C000-000000000046"));
>> mixin( uuid!(IClassFactory,"00000001-0000-0000-C000-000000000046"));
>> 
>> template uuid(T, const char[] g) {
>>      const char [] uuid =
>>          "const IID IID_"~T.stringof~"={ 0x" ~ g[0..8] ~ ",0x" ~ g[9..13] ~ ",0x" ~ g[14..18] ~ ",[0x" ~ g[19..21] ~ ",0x" ~ g[21..23] ~ ",0x" ~ g[24..26] ~ ",0x" ~ g[26..28] ~ ",0x" ~ g[28..30] ~ ",0x" ~ g[30..32] ~ ",0x" ~ g[32..34] ~ ",0x" ~ g[34..36] ~ "]};"~
>>          "template uuidof(T:"~T.stringof~"){"~
>>          "    const IID uuidof ={ 0x" ~ g[0..8] ~ ",0x" ~ g[9..13] ~ ",0x" ~ g[14..18] ~ ",[0x" ~ g[19..21] ~ ",0x" ~ g[21..23] ~ ",0x" ~ g[24..26] ~ ",0x" ~ g[26..28] ~ ",0x" ~ g[28..30] ~ ",0x" ~ g[30..32] ~ ",0x" ~ g[32..34] ~ ",0x" ~ g[34..36] ~ "]};"~
>>          "}";
>> }
>> 
>> //  ----- debuginterface.d -----
>> module debuginterface;
>> 
>> import core.sys.windows.com;
>> import uuidtemplate : uuid; // uuidof
>> 
>> mixin(uuid!(ID3D12Debug, "344488b7-6846-474b-b989-f027448245e0"));
>> interface ID3D12Debug : IUnknown {
>>      void EnableDebugLayer();
>> }
>> 
>> //  ----- comptr.d -----
>> module comptr;
>> public import std.typecons;
>> import core.sys.windows.com;
>> import uuidtemplate : uuid; // uuidof
>> 
>> mixin template IID_PPV_ARGS()
>> {
>>      auto IID_PPV_ARGS(T : ComPtr!U, U)(ref T arg)
>>      {
>>          return tuple(&uuidof!(U), arg.ptrRef());
>>      }
>> 
>>      auto IID_PPV_ARGS(T)(ref T arg)
>>      {
>>          return tuple(&uuidof!(T), &arg);
>>      }
>> }
>> 
>> template ComPtr(T)
>> {
>>      struct ComPtr
>>      {
>>      protected:
>>          T _ptr = null;
>> 
>>      public:
>>          this(ref T inVar)
>>          {
>>              _ptr = inVar;
>>          }
>> 
>>          @property T ptr() { return _ptr; }
>>          @property T* ptrRef() { return &_ptr; }
>> 
>>          alias ptr this;
>>      }
>> }
>> 
>> 
>> //  ----- app.d -----
>> module app;
>> 
>> import core.sys.windows.com;
>> import comptr;
>> import debuginterface;
>> import std.stdio;
>> 
>> // Necessary to mixin since the declaration in comptr.d
>> // cannot see the uuidof declared by debuginterface.
>> // When removing the mixin, it always returns the GUID for IUnknown.
>> mixin IID_PPV_ARGS;
>> 
>> bool D3D12GetDebugInterface(const (GUID)* riid, ID3D12Debug* ppvDebug)
>> {
>>      printf("Guid = {%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}",
>>      riid.Data1, riid.Data2, riid.Data3,
>>      riid.Data4[0], riid.Data4[1], riid.Data4[2], riid.Data4[3],
>>      riid.Data4[4], riid.Data4[5], riid.Data4[6], riid.Data4[7]);
>> 
>>      // output should be: "344488b7-6846-474b-b989-f027448245e0"
>> 
>>      return true;
>> }
>> 
>> void main()
>> {
>>      ComPtr!ID3D12Debug debugController;
>> 
>>      // I want to get rid of the .expand syntax here
>>      if (D3D12GetDebugInterface(IID_PPV_ARGS(debugController).expand))
>>      {
>>          writefln("success!");
>>      }
>> }
>> 
>> /// end code
>> 
>> So my goal here is to get the syntax for IID_PPV_ARGS down to looking just like a function call.
>> 
>> I'd like to get rid of the .expand call. I haven't figured out a better way to express converting the ComPtr input into two outputs used as separate arguments into the outer function.
>> 
>> Any ideas?
>
> Unfortunately, D does not allow you to return an alias sequence directly. So you have to return a struct, which is going to be utilized instead of the alias this'd alias sequence inside the tuple. This is why it's necessary for the expand call.
>
> However, it's not much different to accept the struct than it is to accept the 2 items in the struct. Why not just modify the function D3D12... to accept a struct instead of the 2 parameters? You could even overload it, if you still want to call it directly:
>
> bool D3D12GetDebugInterface(Tuple!(const (GUID)*, ID3D12Debug*) param)
> {
>    return D3D12GetDebugInterface(param.expand);
> }
>
> My preference would be to encompass all the logic for pairing the 2 items together into a specialized struct, not a tuple.
>
> -Steve


I like the idea of an adapter function, but I'm not a huge fan of the prospect to generate adapters for the hundreds of DirectX API calls. I may rethink that as I get deeper into my hobby project.

But now I know there's not a really a way to express the syntax I want.



For my other attempt I did try a mixin:

template IID_PPV_ARGS(alias arg) {
    static if(__traits(isSame, TemplateOf!(typeof(arg)), ComPtr))
    {
        // The arg is a ComPtr, reference the InterfaceType for a typename.
        const char [] IID_PPV_ARGS =
            "from!\"std.typecons\".tuple(&IID_"~arg.InterfaceType.stringof~
            ", "~__traits(identifier, arg)~".ptrRef()).expand";
    }
    else
    {
        // The arg is a pointer, get the typename directly.
        const char [] IID_PPV_ARGS =
            "from!\"std.typecons\".tuple(&IID_"~typeof(arg).stringof~
            ", &"~__traits(identifier, arg)~").expand";
    }
}

ComPtr!ID3D12Debug debugController;
D3D12GetDebugInterface(mixin(IID_PPV_ARGS_mix!(debugController)))



It's still using a tuple.expand, but it writes it in place.

However, I get an error that I don't understand with the variable used is from an array:

// list of command allocators as a class member
ComPtr!ID3D12CommandAllocator[] m_commandAllocators;

// inside a class member function
m_device.CreateCommandAllocator(
    D3D12_COMMAND_LIST_TYPE_DIRECT,
    mixin(IID_PPV_ARGS_mix!(m_commandAllocators[0])));

renderer.d(348,39): Error: value of this is not known at compile time
(this is in bold font)


I'm not sure what this error means. I don't know what it's referring to by "this". As far as I understand, the type of the argument into the alias is a ComPtr!ID3D12CommandAllocator. Another example with a variable of that type from a lone member variable works just fine:

// single command allocators as a class member
ComPtr!ID3D12CommandAllocator m_oneCommandAllocator;

// inside a class member function
m_device.CreateCommandAllocator(
    D3D12_COMMAND_LIST_TYPE_DIRECT,
    mixin(IID_PPV_ARGS_mix!(m_oneCommandAllocator)));


August 30, 2018
On 8/30/18 1:43 AM, Cody Duncan wrote:
> On Wednesday, 29 August 2018 at 16:17:13 UTC, Steven Schveighoffer wrote:
>> On 8/29/18 5:51 AM, Cody Duncan wrote:
>>>  From C++
>>> #define IID_PPV_ARGS(ppType) __uuidof(**(ppType)), IID_PPV_ARGS_Helper(ppType)
>>>
>>> //ComPtr version
>>> ComPtr<ID3D12Debug> debugController;
>>> if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
>>> {
>>>      // do stuff
>>> }
>>>
>>> //Raw Pointer Version
>>> ID3D12Debug* debugController;
>>> if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
>>> {
>>>      // do stuff
>>> }
>>>
>>> IID_PPV_ARGS expands into two arguments of types (const IID &, void**).
>>>
>>> The first arg expansion uses a compiler intrinsic to look up the GUID of the type.
>>>
>>> The second arg expansion uses an IID_PPV_ARGS_Helper, a templated function that return a void**. This either forwards the address of the pointer passed in,
>>> or the result of  ReleaseAndGetAddressOf() from the com object within the ComPtr.
>>>
>>>
>>>
>>> Now in D!
>>> Here is my attempt so far, pared down to just enough to compile "IID_PPV_ARGS(debugController).expand".
>>>
>>> // ----- uuidtemplate.d -----
>>> module uuidtemplate;
>>> import core.sys.windows.com;
>>>
>>> mixin( uuid!(IUnknown, "00000000-0000-0000-C000-000000000046"));
>>> mixin( uuid!(IClassFactory,"00000001-0000-0000-C000-000000000046"));
>>>
>>> template uuid(T, const char[] g) {
>>>      const char [] uuid =
>>>          "const IID IID_"~T.stringof~"={ 0x" ~ g[0..8] ~ ",0x" ~ g[9..13] ~ ",0x" ~ g[14..18] ~ ",[0x" ~ g[19..21] ~ ",0x" ~ g[21..23] ~ ",0x" ~ g[24..26] ~ ",0x" ~ g[26..28] ~ ",0x" ~ g[28..30] ~ ",0x" ~ g[30..32] ~ ",0x" ~ g[32..34] ~ ",0x" ~ g[34..36] ~ "]};"~
>>>          "template uuidof(T:"~T.stringof~"){"~
>>>          "    const IID uuidof ={ 0x" ~ g[0..8] ~ ",0x" ~ g[9..13] ~ ",0x" ~ g[14..18] ~ ",[0x" ~ g[19..21] ~ ",0x" ~ g[21..23] ~ ",0x" ~ g[24..26] ~ ",0x" ~ g[26..28] ~ ",0x" ~ g[28..30] ~ ",0x" ~ g[30..32] ~ ",0x" ~ g[32..34] ~ ",0x" ~ g[34..36] ~ "]};"~
>>>          "}";
>>> }
>>>
>>> //  ----- debuginterface.d -----
>>> module debuginterface;
>>>
>>> import core.sys.windows.com;
>>> import uuidtemplate : uuid; // uuidof
>>>
>>> mixin(uuid!(ID3D12Debug, "344488b7-6846-474b-b989-f027448245e0"));
>>> interface ID3D12Debug : IUnknown {
>>>      void EnableDebugLayer();
>>> }
>>>
>>> //  ----- comptr.d -----
>>> module comptr;
>>> public import std.typecons;
>>> import core.sys.windows.com;
>>> import uuidtemplate : uuid; // uuidof
>>>
>>> mixin template IID_PPV_ARGS()
>>> {
>>>      auto IID_PPV_ARGS(T : ComPtr!U, U)(ref T arg)
>>>      {
>>>          return tuple(&uuidof!(U), arg.ptrRef());
>>>      }
>>>
>>>      auto IID_PPV_ARGS(T)(ref T arg)
>>>      {
>>>          return tuple(&uuidof!(T), &arg);
>>>      }
>>> }
>>>
>>> template ComPtr(T)
>>> {
>>>      struct ComPtr
>>>      {
>>>      protected:
>>>          T _ptr = null;
>>>
>>>      public:
>>>          this(ref T inVar)
>>>          {
>>>              _ptr = inVar;
>>>          }
>>>
>>>          @property T ptr() { return _ptr; }
>>>          @property T* ptrRef() { return &_ptr; }
>>>
>>>          alias ptr this;
>>>      }
>>> }
>>>
>>>
>>> //  ----- app.d -----
>>> module app;
>>>
>>> import core.sys.windows.com;
>>> import comptr;
>>> import debuginterface;
>>> import std.stdio;
>>>
>>> // Necessary to mixin since the declaration in comptr.d
>>> // cannot see the uuidof declared by debuginterface.
>>> // When removing the mixin, it always returns the GUID for IUnknown.
>>> mixin IID_PPV_ARGS;
>>>
>>> bool D3D12GetDebugInterface(const (GUID)* riid, ID3D12Debug* ppvDebug)
>>> {
>>>      printf("Guid = {%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}",
>>>      riid.Data1, riid.Data2, riid.Data3,
>>>      riid.Data4[0], riid.Data4[1], riid.Data4[2], riid.Data4[3],
>>>      riid.Data4[4], riid.Data4[5], riid.Data4[6], riid.Data4[7]);
>>>
>>>      // output should be: "344488b7-6846-474b-b989-f027448245e0"
>>>
>>>      return true;
>>> }
>>>
>>> void main()
>>> {
>>>      ComPtr!ID3D12Debug debugController;
>>>
>>>      // I want to get rid of the .expand syntax here
>>>      if (D3D12GetDebugInterface(IID_PPV_ARGS(debugController).expand))
>>>      {
>>>          writefln("success!");
>>>      }
>>> }
>>>
>>> /// end code
>>>
>>> So my goal here is to get the syntax for IID_PPV_ARGS down to looking just like a function call.
>>>
>>> I'd like to get rid of the .expand call. I haven't figured out a better way to express converting the ComPtr input into two outputs used as separate arguments into the outer function.
>>>
>>> Any ideas?
>>
>> Unfortunately, D does not allow you to return an alias sequence directly. So you have to return a struct, which is going to be utilized instead of the alias this'd alias sequence inside the tuple. This is why it's necessary for the expand call.
>>
>> However, it's not much different to accept the struct than it is to accept the 2 items in the struct. Why not just modify the function D3D12... to accept a struct instead of the 2 parameters? You could even overload it, if you still want to call it directly:
>>
>> bool D3D12GetDebugInterface(Tuple!(const (GUID)*, ID3D12Debug*) param)
>> {
>>    return D3D12GetDebugInterface(param.expand);
>> }
>>
>> My preference would be to encompass all the logic for pairing the 2 items together into a specialized struct, not a tuple.
>>
> 
> 
> I like the idea of an adapter function, but I'm not a huge fan of the prospect to generate adapters for the hundreds of DirectX API calls. I may rethink that as I get deeper into my hobby project.

Adapters may be possible to generate automatically with a mixin and a function name.

> However, I get an error that I don't understand with the variable used is from an array:
> 
> // list of command allocators as a class member
> ComPtr!ID3D12CommandAllocator[] m_commandAllocators;
> 
> // inside a class member function
> m_device.CreateCommandAllocator(
>      D3D12_COMMAND_LIST_TYPE_DIRECT,
>      mixin(IID_PPV_ARGS_mix!(m_commandAllocators[0])));
> 
> renderer.d(348,39): Error: value of this is not known at compile time
> (this is in bold font)
> 
> 
> I'm not sure what this error means. I don't know what it's referring to by "this". As far as I understand, the type of the argument into the alias is a ComPtr!ID3D12CommandAllocator. Another example with a variable of that type from a lone member variable works just fine:
> 
> // single command allocators as a class member
> ComPtr!ID3D12CommandAllocator m_oneCommandAllocator;
> 
> // inside a class member function
> m_device.CreateCommandAllocator(
>      D3D12_COMMAND_LIST_TYPE_DIRECT,
>      mixin(IID_PPV_ARGS_mix!(m_oneCommandAllocator)));
> 
> 

I think because you can't alias an indexed item from the struct. Aliases must strictly be symbols, not arbitrary expressions. Essentially, it's trying to evaluate m_commandAllocators[0], then take an alias to that. It can't evaluate the expression at compile time, so it gives up.

Possibly, you could create an inner function that returns it, and alias that function, but I'm not sure whether it would work.

e.g.:

auto getIt() { return m_commandAllocators[0]; }

...mixin(IID_PPV_ARGS_mix!(getIt)))

-Steve