www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Mimicking IID_PPV_ARGS

reply Cody Duncan <dlang codyduncan.net> writes:
 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?
Aug 29 2018
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
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
Aug 29 2018
parent reply Cody Duncan <dlang codyduncan.net> writes:
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)));
Aug 29 2018
parent Steven Schveighoffer <schveiguy gmail.com> writes:
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
Aug 30 2018