www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - this() member function?

reply Wei Li <wstring gmail.com> writes:
Content-Type: text/plain

Hi:

The following code is a quick and dirty variant implemention inspired by
boost.variant. It works, but why is the constructor(this(T)()) cannot to be a
template function?

//variant.d
module variant;

import std.stdio;
import std.metastrings;
import std.typetuple;

private template MixinMembers(int L, T, V...)
{
    mixin(Format!("%s var%s;", T.stringof, L - 1 - V.length));

    static if(V.length > 0)
        mixin MixinMembers!(L, V);
}

//catenate strings at compile time....
private template MixinThisFunc(char[] S, T, V...)
{
    public const char[] Result = S ~ 
        Format!("public this(%s v) { assign!(%s)(v); } ", T.stringof,
T.stringof);
    pragma(msg, Result ~ "\n");
    static if(V.length > 0)
        mixin MixinThisFunc!(Result, V);
}

class Variant(TList...)
{
    public alias TList  TypeList;
    public alias Variant!(TList)    SelfType;

    private union Holder
    {
        mixin MixinMembers!(TList.length, TList);
    }

    private Holder m_holder;
    private int m_which = -1;
    
    public mixin(MixinThisFunc!("",TypeList).Result);

    public this()
    {
        m_holder.var0 = m_holder.var0.init;
        m_which = 0;
    }

    public SelfType assign(T)(T rhs)
    {
        enum { index =  IndexOf!(T, TypeList) }
        static assert( index >= 0);
        mixin(Format!("m_holder.var%s = rhs;", index));
        m_which = index;
        return this;
    }

    public SelfType opAssign(T)(T rhs)
    {
        return assign(rhs);
    }

    public int which()
    {
        return m_which;
    }

    public T get(T)()
    {
        enum { index = IndexOf!(T, TypeList) }
        static assert(index >= 0);
        assert(index == which());
        mixin(Format!("return m_holder.var%s;", index));
    }
}

void main()
{
    scope auto v = new Variant!(int, double, char, char[])(1000);
    writefln("which: %d", v.which());
    v = 100.0;
    v = 'A';
    writefln("which: %d", v.which());
    char[] str = "foobar";
    v = str;
    writefln("which: %d", v.which());
    str = "";
    str = v.get!(char[]);
    writefln(str);
}
             - Wei Li
Feb 24 2007
next sibling parent Wei Li <wstring gmail.com> writes:
The fixed version:

import std.stdio;
import std.metastrings;
import std.typetuple;

private template MixinMembers(int I, T, V...)
{
    mixin(Format!("T var%s;", I));

    static if(V.length > 0)
        mixin MixinMembers!(I + 1, V);
}

//catenate strings at compile time....
private template MixinThisFunc(char[] S, T, V...)
{
    public const char[] Result = S ~ 
        Format!("public this(%s v) { assign!(%s)(v); } ", T.stringof,
T.stringof);
    pragma(msg, Result ~ "\n");
    static if(V.length > 0)
        mixin MixinThisFunc!(Result, V);
}

class Variant(TList...)
{
    public alias TList  TypeList;
    public alias Variant!(TList)    SelfType;

    // no union.tupleof?
    private union Holder
    {
        mixin MixinMembers!(0, TList);
    }

    private Holder m_holder;
    private int m_which = -1;
    
    public mixin(MixinThisFunc!("",TypeList).Result);

    public this()
    {
        m_holder.var0 = m_holder.var0.init;
        m_which = 0;
    }

    public SelfType assign(T)(T rhs)
    {
        enum { index =  IndexOf!(T, TypeList) }
        static assert( index >= 0);
        mixin(Format!("m_holder.var%s = rhs;", index));
        m_which = index;
        return this;
    }

    public SelfType opAssign(T)(T rhs)
    {
        return assign(rhs);
    }

    public int which()
    {
        return m_which;
    }

    public T get(T)()
    {
        enum { index = IndexOf!(T, TypeList) }
        static assert(index >= 0);
        assert(index == which());
        mixin(Format!("return m_holder.var%s;", index));
    }
}

void main()
{
    scope auto v = new Variant!(int, double, char, char[])(1000);
    writefln("which: %d", v.which());
    v = 100.0;
    v = 'A';
    writefln("which: %d", v.which());
    char[] str = "foobar";
    v = str;
    writefln("which: %d", v.which());
    str = "";
    str = v.get!(char[]);
    writefln(str);
}
Feb 24 2007
prev sibling next sibling parent Marcin Kuszczak <aarti interia.pl> writes:
Wei Li wrote:

 Hi:
 
 The following code is a quick and dirty variant implemention inspired by
 boost.variant. It works, but why is the constructor(this(T)()) cannot to
 be a template function?
 

Very nice! You just did not mentioned that your implementation is about 80 times more compact than Boost version :-) I had same experience when porting from boost... -- Regards Marcin Kuszczak (Aarti_pl) ------------------------------------- Ask me why I believe in Jesus - http://zapytaj.dlajezusa.pl (en/pl) Doost (port of few Boost libraries) - http://www.dsource.org/projects/doost/ -------------------------------------
Feb 24 2007
prev sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Wei Li wrote:
 Hi:
 
 The following code is a quick and dirty variant implemention inspired by
boost.variant. It works, but why is the constructor(this(T)()) cannot to be a
template function?
 
 //variant.d
 module variant;
 ...

So now we have std.boxer, and there's a port of boost::Any floating around. How do all those differ from one another? --bb
Feb 24 2007
parent Marcin Kuszczak <aarti interia.pl> writes:
Bill Baxter wrote:

 Wei Li wrote:
 Hi:
 
 The following code is a quick and dirty variant implemention inspired by
 boost.variant. It works, but why is the constructor(this(T)()) cannot to
 be a template function?
 
 //variant.d
 module variant;
 ...

So now we have std.boxer, and there's a port of boost::Any floating around. How do all those differ from one another? --bb

Let me comment on this: Boxer - this is done on struct so it is very fast. I would say if it would be fixed it should be still standard implementation. But there should be few issues fixed in this implementation: a. to get information that container is empty you have check if type is null. There should be really method empty() to check this b. I would also suggest to add method clear() for consistency c. There is ugly bug #8 which effectively makes boxer unusable under linux Any - universal and clean implementation. Unfortunatelly about 10 times slower than boxer for 'int's... Variant - Similar to any but you can limit data types stored inside container to few choosen types. -- Regards Marcin Kuszczak (Aarti_pl) ------------------------------------- Ask me why I believe in Jesus - http://zapytaj.dlajezusa.pl (en/pl) Doost (port of few Boost libraries) - http://www.dsource.org/projects/doost/ -------------------------------------
Feb 24 2007