Межмодульная ошибка разрешения символа типа-параметра шаблона при использовании mixins
В
Я реализовал легкий массив полиморфных массивов, который я называю VariantArrays(Types...)
индексируется соответствующим полиморфным индексом, который я называю VariantIndex(Types...)
,
Оно использует .mangleof
вместе с mixins для автоматического определения определения (включая его имя) каждого хранилища массива для каждого типа элемента в Types
, Типы элементов передаются в параметре шаблона. Types
к двум шаблонным структурам, упомянутым выше.
Все работает, кроме случаев, когда я пытаюсь создать экземпляр VariantArrays
из другого модуля, кроме variant_arrays.d
, Например, если я попытаюсь использовать его в другом модуле, содержащем
unittest
{
struct S { int x; }
import variant_arrays : VariantArrays;
VariantArrays!S a;
}
Я получаю ошибку
variant_arrays.d-mixin-130(130,1): Error: undefined identifier `S`
foo.d(5,5): Error: template instance variant_arrays.VariantArrays!(S) error instantiating
Другими словами, символ S
не может быть решена в рамках VariantArrays
хотя это подача в качестве параметра шаблона.
Есть ли способ обойти эту проблему?
Опубликовано также здесь: http://forum.dlang.org/post/einvuqvpeoeubkwhwbbm@forum.dlang.org
Здесь следует определение variant_arrays.d
(исключая юнит-тесты):
/** 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;
}());
}