Disabling opAssign in a type disabled all the opAssigns of an aliased type?

aliak something at something.com
Mon Jul 30 23:41:09 UTC 2018


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




More information about the Digitalmars-d-learn mailing list