Thread overview
this() member function?
Feb 24, 2007
Wei Li
Feb 24, 2007
Wei Li
Feb 24, 2007
Marcin Kuszczak
Feb 24, 2007
Bill Baxter
Feb 24, 2007
Marcin Kuszczak
February 24, 2007
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



February 24, 2007
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);
}

February 24, 2007
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/
-------------------------------------

February 24, 2007
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
February 24, 2007
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/
-------------------------------------