Inter-module symbol resolution error of template type-parameter when using mixins

Nordlöw per.nordlow at gmail.com
Wed Sep 27 18:24:04 UTC 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;
         }());
}



More information about the Digitalmars-d-learn mailing list