On Tuesday, 24 October 2017 at 11:37:42 UTC, Per Nordlöw wrote:
On Tuesday, 24 October 2017 at 07:56:34 UTC, Biotronic wrote:
struct SuppressPostblit(T)
{
    // Disguise T as a humble array.
    private ubyte[T.sizeof] _payload;
...

A bit too hackish for my taste, but does the job still.

Thanks.

Cleaned up and slightly less hackish (yeah, it bothered me too):

enum SuppressOptions {
    destructor = 1,
    postblit = 2
}

struct Suppress(T, SuppressOptions options) if (options != 0)
{
    import std.traits : isCopyable;
private enum suppressPostblit = (options & SuppressOptions.postblit) != 0; private enum suppressDestructor = (options & SuppressOptions.destructor) != 0; private enum postblitName = __traits(hasMember, T, "__xpostblit") ? "__xpostblit" : "__postblit";

    // Disguise T as a humble array.
    private ubyte[T.sizeof] _payload;

    // Create from instance of T.
    this(T arg) {
        _payload = *cast(ubyte[T.sizeof]*)&arg;
    }

    // Or forward constructor arguments to T's constructor.
    static if (__traits(hasMember, T, "__ctor"))
    {
        this(Args...)(Args args)
if (__traits(compiles, (Args e){__traits(getMember, T.init, "__ctor")(e);}))
        {
            __traits(getMember, get, "__ctor")(args);
        }
    }

    // Call dtor
    static if (!suppressDestructor) {
        ~this() {
            destroy(get);
        }
    }

    // Call postblit
    static if (!suppressPostblit) {
        static if (!isCopyable!T) {
            @disable this(this);
        } else static if (__traits(hasMember, T, postblitName)) {
            this(this) {
                __traits(getMember, get, postblitName)();
            }
        }
    }

    // Pretend to be a T.
    @property
    ref T get()
    {
        return *cast(T*)_payload.ptr;
    }

    alias get this;
}

struct S1 {
    @disable this(this);
    ~this() {
        throw new Exception("Don't touch my destructor!");
    }
}

unittest {
    import std.exception;
static assert(!__traits(compiles, (Suppress!S1 a) { auto b = a; })); static assert(__traits(compiles, (Suppress!(S1, SuppressOptions.postblit) a) { auto b = a; }));

assertThrown({ Suppress!(S1, SuppressOptions.postblit) a; }()); assertNotThrown({ Suppress!(S1, SuppressOptions.postblit | SuppressOptions.destructor) a; }());
}

--
  Biotronic

Reply via email to