www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - What is the correct way to forward method calls to the struct field?

reply "monnoroch" <monnoroch gmail.com> writes:
I tried this:

struct S {
	R opDispatch(string name, R, Args...)(Args args) {
		return mixin("(*iface)." ~ name)(iface, args);
	}
	SomeT ** iface;
}

But then val.foo(1, 2) gives me "no property 'foo' for type 'S'".

I've seen the template solution:

struct S {
	template opDispatch(string name) {
		R opDispatch(R, Args...)(Args args) {
			return mixin("(*iface)." ~ name)(iface, args);
		}
	}
	SomeT ** iface;
}

But that does not seem to work anymore.

I've tried then

struct S {
	auto ifc() {
		return *iface;
	}

	auto ifc() const {
		return *iface;
	}
	
	SomeT ** iface;
}

And that worked, but it's not perfect: i also want to pass iface
as a first argument.

val.foo(1, 2) -> (*val.iface).foo(val.iface, 1, 2).

Any suggestions?
Jun 21 2014
parent reply "monnoroch" <monnoroch gmail.com> writes:
Actyaly, last variant didn't work either: i was testing it
inside S like "ifc.foo(1)", so UFCS kiked in, not alias this.
Jun 21 2014
parent reply "monnoroch" <monnoroch gmail.com> writes:
On Saturday, 21 June 2014 at 18:16:17 UTC, monnoroch wrote:
 Actyaly, last variant didn't work either: i was testing it
 inside S like "ifc.foo(1)", so UFCS kiked in, not alias this.
Oh, my bad, "alias impl this;" actually did work. But the first argument problem still holds.
Jun 21 2014
parent reply Philippe Sigaud via Digitalmars-d-learn writes:
You can use 'auto' to let the compiler deduce the return type. Here I
use 'foo' which returns an int and 'bar', which returns void.

struct SomeT {
    int foo(double d) { return 0;}
    void bar(double d) { return;}
}

struct S {
    auto /* here */
       opDispatch(string name, Args...)(Args args) {
        return mixin("(*iface)." ~ name)(args);
    }
    SomeT** iface;
}


void main()
{
  SomeT st;
  SomeT* st_p = &st;
  SomeT** st_p_p = &st_p;

  S s = S(st_p_p);

  import std.stdio : writeln;
  writeln(s.foo(3.14)); // "0"
  writeln(typeof(s.bar(3.14)).stringof); // "void"
}

On Sat, Jun 21, 2014 at 8:21 PM, monnoroch via Digitalmars-d-learn
<digitalmars-d-learn puremagic.com> wrote:
 On Saturday, 21 June 2014 at 18:16:17 UTC, monnoroch wrote:
 Actyaly, last variant didn't work either: i was testing it
 inside S like "ifc.foo(1)", so UFCS kiked in, not alias this.
Oh, my bad, "alias impl this;" actually did work. But the first argument problem still holds.
Jun 21 2014
parent reply "monnoroch" <monnoroch gmail.com> writes:
Thanks a lot!
There is a problem though: when i pass incorrect parameters to
such a method, it says, that S has no such field, which is a
misleading error message.
Jun 22 2014
next sibling parent reply "monnoroch" <monnoroch gmail.com> writes:
There is also a problem: when i declare opDispatch to be private,
i still have access to this forwarding from another package. Is
it a bug or what?
Jun 22 2014
parent Philippe Sigaud via Digitalmars-d-learn writes:
On Sun, Jun 22, 2014 at 5:04 PM, monnoroch via Digitalmars-d-learn
<digitalmars-d-learn puremagic.com> wrote:
 There is also a problem: when i declare opDispatch to be private,
 i still have access to this forwarding from another package. Is
 it a bug or what?
I don't know. I never used private in conjunction with a template. Let's hope someone more knowledgeable than me can answer this.
Jun 22 2014
prev sibling parent reply Philippe Sigaud via Digitalmars-d-learn writes:
On Sun, Jun 22, 2014 at 5:02 PM, monnoroch via Digitalmars-d-learn
<digitalmars-d-learn puremagic.com> wrote:
 Thanks a lot!
 There is a problem though: when i pass incorrect parameters to
 such a method, it says, that S has no such field, which is a
 misleading error message.
You can test the mixin with static if, like this: struct SomeT { int foo(double d) { return 0;} void bar(double d) { return;} } struct S { auto opDispatch(string name, Args...)(Args args) { static if (is(typeof(mixin("(*iface)." ~ name)(args)))) return mixin("(*iface)." ~ name)(args); else pragma(msg, "S." ~ name ~ " cannot be called with arguments of type " ~ Args.stringof); } SomeT** iface; } void main() { SomeT st; SomeT* st_p = &st; SomeT** st_p_p = &st_p; S s = S(st_p_p); s.foo(3.14); s.foo("abc"); s.bar("abc", 3.14); }
Jun 22 2014
parent reply "monnoroch" <monnoroch gmail.com> writes:
Cool! Only this does not show me where the error was. __FILE__
and __LINE__ is not any help here, because it's a template. Any
other way to find out where the actual error was?
Jun 22 2014
parent "monnoroch" <monnoroch gmail.com> writes:
Nah, this gives me lots of compiler crap, like .empty and others,
when compiler tries to compile them.
Jun 22 2014