On Monday, 30 July 2018 at 20:54:28 UTC, Simen Kjærås wrote:
On Monday, 30 July 2018 at 18:30:16 UTC, aliak wrote:
Is this a bug?

If not is there a workaround?

I would like for the alias this to function as a normal A type unless B specifically disables certain features, but it seems weird that disabling one opAssign disables all of them inside the aliases type but not in the aliasing type?


struct A {
    void opAssign(int) {}
}
struct B {
    A a;
    alias a this;
    @disable void opAssign(float);
}

void main() {
    B b;
    b = 3;
}

Error: function `onlineapp.B.opAssign` is not callable because it is annotated with @disable


The workaround is to not disable opAssign. :p

Since this does work for other member functions that opAssign, I'm gonna say it's a bug - please file it in Bugzilla.

A perhaps better workaround than the above is to wrap A's opAssigns. Sadly, this can't be done with template mixins, since they don't overload with non-mixins. It can be done with string mixins, however. It's also possible to encapsulate all this in a nice little template:

struct A {
    void opAssign(int) {}
    void opAssign(float) {}
}
struct B {
    A a;
    alias a this;
    @disable void opAssign(float);
    mixin(wrap!(B, "opAssign"));
}

string wrap(T, string methodName)() {
    enum targetName = __traits(getAliasThis, T)[0];
    return `import std.traits : Parameters, ReturnType;
static foreach (e; __traits(getOverloads, typeof(`~targetName~`), "`~methodName~`")) static if (!is(typeof({static assert(__traits(isDisabled, getOverload!(typeof(this), "`~methodName~`", Parameters!e)));})))
            ReturnType!e `~methodName~`(Parameters!e args) {
return __traits(getMember, `~targetName~`, "`~methodName~`")(args);
            }`;
}

template getOverload(T, string name, Args...) {
    import std.traits : Parameters;
    import std.meta : AliasSeq;
    template impl(overloads...) {
        static if (overloads.length == 0) {
            alias impl = AliasSeq!();
} else static if (is(Parameters!(overloads[0]) == Args)) {
            alias impl = overloads[0];
        } else {
            alias impl = impl!(overloads[1..$]);
        }
    }
    alias getOverload = impl!(__traits(getOverloads, T, name));
}

unittest {
    B b;
    b = 3;
    static assert(!__traits(compiles, b = 3f));
}

And that's enough magic for me for one night.

--
  Simen

Heheh .... Amazing! In today's episode of extreme D (why is that not a thing?), we give you a "nice little template" :p

https://issues.dlang.org/show_bug.cgi?id=19130

Would it take much to fix it up to use with templated opAssigns as well?

I tried for a bit and got stuck with trying to get parameters and now I'm giving up for the time being.

struct A {
    void opAssign(int) {}
    void opAssign()(float) {}
}
struct B(T) {
    A a;
    alias a this;
    @disable void opAssign(U)(B!U);

    import std.traits : Parameters, ReturnType;
static foreach (t; __traits(getOverloads, A, "opAssign", true)) {
        static if (is(typeof(t.stringof))) {
            pragma(msg, t.stringof, " - ", Parameters!t);
        } else {
            pragma(msg, typeof(t), " - ", Parameters!t);
        }
    }
}

The Parameters!t of the template overloads all come out as "int" but only if there's the non-template opAssign(int) in A. If you remove that then you get errors. So something is fishy.

Also I realized that it's just 2 opAssigns in the aliased Optional!T type for my specific use case so maybe, err... copy pasta them in.

Cheers,
- Ali


Reply via email to