September 27, 2017
At

https://github.com/nordlow/phobos-next/blob/03b4736fdd65ef84c6fc583eddee4196629cea81/src/variant_arrays.d

I've implemented a lightweight-polymorphic array container I call `VariantArrays(Types...)` indexed by a corresponding polymorphic index I call `VariantIndex(Types...)`.

It uses `.mangleof` together with mixins to automatically infer the definition (including its name) of each array store for each element type in `Types`. The element types are passed in the template parameter `Types` to the two templated structs mentioned above.

Everything works except for when I try to instantiate `VariantArrays` from within a module other than `variant_arrays.d`. For instance, if I try to use it another module containing

unittest
{
    struct S { int x; }
    import variant_arrays : VariantArrays;
    VariantArrays!S a;
}

I get the error

variant_arrays.d-mixin-130(130,1): Error: undefined identifier `S`
foo.d(5,5): Error: template instance variant_arrays.VariantArrays!(S) error instantiating

In other words, the symbol `S` cannot be resolved in the scope of `VariantArrays` eventhough it's feed as a template parameter.

Is there a way around this problem?

Here follows the definition of variant_arrays.d (excluding unittests):

/** Polymorphic index into an element in `VariantArrays`. */
private struct VariantIndex(Types...)
{
    import std.meta : staticIndexOf;
private:
    alias Kind = ubyte;              // kind code
    alias Size = size_t;             // size type

    import bit_traits : bitsNeeded;

    /// Number of bits needed to represent kind.
    enum kindBits = bitsNeeded!(Types.length);

    /// Get number kind of kind type `SomeKind`.
    enum nrOfKind(SomeKind) = staticIndexOf!(SomeKind, Types); // TODO cast to ubyte if Types.length is <= 256

    /// Is `true` iff an index to a `SomeKind`-kind can be stored.
    enum canReferTo(SomeKind) = nrOfKind!SomeKind >= 0;

    /// Construct.
    this(Kind kind, Size index) // TODO can ctor inferred by bitfields?
    {
        _kindNr = kind;
        _index = index;
    }

    import std.bitmanip : bitfields;
    mixin(bitfields!(Size, "_index", 8*Size.sizeof - kindBits,
                     Kind, "_kindNr", kindBits));
}

/** Stores set of variants.

    Enables lightweight storage of polymorphic objects.

    Each element is indexed by a corresponding `VariantIndex`.
 */
private struct VariantArrays(Types...)
{
    alias Index = VariantIndex!Types;

    import basic_copyable_array : CopyableArray;

    /// Returns: array type (as a string) of `Type`.
    private static immutable(string) arrayTypeString(Type)()
    {
        return `CopyableArray!(` ~ Type.stringof ~ `)`;
    }

    /// Returns: array instance (as a strinng) storing `Type`.
    private static immutable(string) arrayInstanceString(Type)()
    {
        return `_values` ~ Type.mangleof;
    }

    /** Insert `value` at back.
     */
    pragma(inline)                             // DMD cannot inline
    Index insertBack(SomeKind)(SomeKind value) // TODO add array type overload
        if (Index.canReferTo!SomeKind)
    {
        mixin(`alias arrayInstance = ` ~ arrayInstanceString!SomeKind ~ `;`);
        const currentIndex = arrayInstance.length;
        arrayInstance.insertBack(value);
        return Index(Index.nrOfKind!SomeKind,
                     currentIndex);
    }
    alias put = insertBack;     // polymorphic `OutputRange` support

    /// Get reference to element of type `SomeKind` at `index`.
    scope ref inout(SomeKind) at(SomeKind)(in size_t index) inout return
        if (Index.canReferTo!SomeKind)
    {
        mixin(`return ` ~ arrayInstanceString!SomeKind ~ `[index];`);
    }

    /// Peek at element of type `SomeKind` at `index`.
    scope inout(SomeKind)* peek(SomeKind)(in Index index) inout return @system
        if (Index.canReferTo!SomeKind)
    {
        if (Index.nrOfKind!SomeKind == index._kindNr)
        {
            return &at!SomeKind(index._index);
        }
        else
        {
            return null;
        }
    }

private:
    // TODO this fails:
    mixin({
            string s = "";
            foreach (Type; Types)
            {
                s ~= arrayTypeString!Type ~ ` ` ~ arrayInstanceString!Type ~ `;`;
            }
            return s;
        }());
}

September 28, 2017
On Wednesday, 27 September 2017 at 18:24:04 UTC, Nordlöw wrote:
> At ...

Thanks Adam for your advice at

https://stackoverflow.com/questions/46454887/inter-module-symbol-resolution-error-of-template-type-parameter-when-using-mixin?noredirect=1#comment79867792_46454887

I made things work in this version

https://github.com/nordlow/phobos-next/blob/ef7e4fd59725400b4f1552f1f21cef050550a8a4/src/variant_arrays.d

by using

private static immutable(string) arrayTypeStringOfIndex(uint typeIndex)()
{
    return `CopyableArray!(Types[` ~ typeIndex.stringof ~ `])`;
}

instead of the previous

private static immutable(string) arrayTypeString(Type)()
{
    return `CopyableArray!(` ~ Type.stringof ~ `)`;
}