On 05/06/2015 10:01 AM, Andrei Alexandrescu wrote:
Consider:

void fun()
{
     int x;
     class C
     {
         ...
     }
}

Objects of type C have access to x because they have an .outer
pseudo-member.

Problem is, emplace() and any other in-situ initialization techniques
fail (e.g. emplace() will fail with inner classes).

This seems to be a compiler issue - there's no way to initialize outer
without calling new.


The following workaround seems to do it (I didn't test it thoroughly though, in particular, I didn't test whether escape analysis always works correctly for this implementation):

T nestedEmplace(T,alias x,S...)(void[] mem,S args){
    auto res=cast(T)mem.ptr;
    enum siz=__traits(classInstanceSize, T);
    (cast(byte[])mem)[0..siz]=typeid(T).init[];
    auto dg=(){ return x; };
    res.outer=dg.ptr;
    static if(is(typeof(res.__ctor(args)))) res.__ctor(args);
    else assert(!is(typeof(&res.__ctor))&&args.length==0);
    return res;
}

void main(){
    int x=12345;
    class C{
        this(){}
        int foo(){
            return x;
        }
    }
    void[__traits(classInstanceSize,C)] mem=void;
    auto c=nestedEmplace!(C,x)(mem);
    assert(c.foo()==12345);
    x=3;
    assert(c.foo()==3);
}


What would be a proper fix to this?


Probably nested types should invoke nested template instantiation, as the context pointer is runtime data. Then add a way to access the context pointer associated with some symbol (e.g. __traits).


Thanks,

Andrei

Reply via email to