www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - inout and templates don't mix...

reply cy <dlang verge.info.tm> writes:
halp

There's a module that tries to define complex operations on both 
const and non-const structs, since it's the same operation for 
both. So every function that invokes those operations is 
copy-pasted twice, just with "const" added. Switching to inout to 
eliminate that huge amount of code duplication causes an error, I 
can't figure out how to fix.

struct Someop(Type) {
   Type thing;
   void foo() {
	thing.bar();
   }
}

struct Foo {
   void bar() {
	import std.stdio: writeln;
	writeln("bar");
   }
}

struct Bar {
   void thingy(inout(Foo) foo) inout {
	auto op = Someop(foo);
	op.foo();
   }
}

void main() {
   Foo foo;
   Bar bar;
   bar.thingy(foo);
}

=>

Error: struct derp.Someop cannot deduce function from argument 
types !()(inout(Foo))

if I put in Someop!(typeof(foo))(foo) it gives the error:

Error: variable derp.Someop!(inout(Foo)).Someop.thing only 
parameters or stack based variables can be inout

...even though Someop is a struct allocated on the stack.

What I'm dealing with is like:

struct Bar {
   void thingy(Foo foo) {
	auto op = Someop(foo);
	//...lotsastuff...
	op.foo();
   }
   void thingy(const(Foo) foo) const {
	auto op = Someop(foo);
	//...lotsastuff...
	op.foo();
   }
   // repeat ad-nauseum...
}
Mar 23 2016
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 03/23/2016 02:31 PM, cy wrote:

 struct Someop(Type) {
    Type thing;
    void foo() {
      thing.bar();
    }
 }

 struct Foo {
    void bar() {
      import std.stdio: writeln;
      writeln("bar");
    }
 }

 struct Bar {
    void thingy(inout(Foo) foo) inout {
      auto op = Someop(foo);
The following is a workaround for this example: auto op = Someop!Foo(foo); I'm not sure whether Someop's implicit constructor should take part in deducing Someop's Type template parameter. Ali
Mar 23 2016
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/23/16 6:25 PM, Ali Çehreli wrote:
 On 03/23/2016 02:31 PM, cy wrote:

  > struct Someop(Type) {
  >    Type thing;
  >    void foo() {
  >      thing.bar();
  >    }
  > }
  >
  > struct Foo {
  >    void bar() {
  >      import std.stdio: writeln;
  >      writeln("bar");
  >    }
  > }
  >
  > struct Bar {
  >    void thingy(inout(Foo) foo) inout {
  >      auto op = Someop(foo);

 The following is a workaround for this example:

        auto op = Someop!Foo(foo);
I would be surprised if the original code worked regardless of inout status. Struct implicit ctors are not IFTI-compatible. Note what is happening here in your update is likely not what the OP expects. Since Foo contains no indirections, it is a value type. So it can be implicitly cast from inout to mutable (same thing with Someop). As soon as you involve a pointer here, it would stop compiling.
 I'm not sure whether Someop's implicit constructor should take part in
 deducing Someop's Type template parameter.
There is no deduction. However, you can specify that you are explicitly constructing an inout Someop: auto op = inout(Someop!Foo)(foo); However, this will not allow Bar to compile, since it calls op.foo, and Someop.foo is not inout, neither is Foo.bar, so neither can be called. In this case, you need to mark Foo.bar and Someop.foo as inout. Marking Foo.bar as inout is probably acceptable, but marking Someop.foo as inout is tricky, since it's a wrapper, and can't predict what Type is going to allow. This is one of the viral situations that frankly affects all the mutability modifiers. -Steve
Mar 24 2016