Variant and immutable struct
Vlad Leberstein via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Sun Jan 10 09:50:44 PST 2016
Okay, I've cleared up some misconception.
On Wednesday, 6 January 2016 at 03:22:47 UTC, Vlad Leberstein
wrote:
> The same happens with immutable class(there is related thread
> with workaround at
> http://www.digitalmars.com/d/archives/digitalmars/D/learn/Sending_an_immutable_object_to_a_thread_73866.html)
This is irrelevant here.
On Wednesday, 6 January 2016 at 03:22:47 UTC, Vlad Leberstein
wrote:
> I'm trying to put an immutable struct into std.variant.Variant
> but get some compilation error(but only when struct has at
> least one member). Stripped down example(tested on Linux dmd64
> v2.069.2):
>
> import std.variant : Variant;
>
>
> immutable struct Test {
> int member;
> }
>
> int main() {
> Test v;
> Variant test = v;
> return 0;
> }
>
Qualifier applied to definition of aggregate type just marks all
it's members with the qualifier and doesn't change the type
itself(as I thought initially).
So the problem with current implementation of std.variant.Variant
is that it tries to modify(from the point of view of Type System)
existing struct instance containing immutable members. I've done
a little bit of hacking on Variant and came up with the following
modification of "tryPutting":
...
static bool tryPutting(A* src, TypeInfo targetType, void* target)
{
alias UA = Unqual!A;
alias MutaTypes = TypeTuple!(UA,
ImplicitConversionTargets!UA);
alias ConstTypes = staticMap!(ConstOf, MutaTypes);
alias SharedTypes = staticMap!(SharedOf, MutaTypes);
alias SharedConstTypes = staticMap!(SharedConstOf,
MutaTypes);
alias ImmuTypes = staticMap!(ImmutableOf, MutaTypes);
static if (is(A == immutable))
alias AllTypes = TypeTuple!(ImmuTypes,
ConstTypes, SharedConstTypes);
else static if (is(A == shared))
{
static if (is(A == const))
alias AllTypes = SharedConstTypes;
else
alias AllTypes = TypeTuple!(SharedTypes,
SharedConstTypes);
}
else
{
static if (is(A == const))
alias AllTypes = ConstTypes;
else
alias AllTypes = TypeTuple!(MutaTypes,
ConstTypes);
}
foreach (T ; AllTypes)
{
if (targetType != typeid(T))
{
continue;
}
static if (is(typeof(*cast(T*) target = *src)))
{
T* zat = cast(T*) target;
if (src)
{
assert(target, "target must be non-null");
*zat = *src;
}
}
else static if ((is(T == const(U), U) ||
is(T == shared(U), U) ||
is(T == shared const(U), U) ||
is(T == immutable(U), U)) &&
is(typeof(*(cast(U*) (target)) =
*(cast(UA*) src)))
)
{
U* zat = cast(U*) target;
if (src)
{
assert(target, "target must be non-null");
*zat = *(cast(UA*) (src));
}
}
else static if(is(T == struct))
{
if (src)
{
assert(target, "target must be non-null");
memcpy((cast(void*) target), (cast(const(void*)) src),
A.sizeof);
}
}
else
{
// type is not assignable
if (src) assert(false, A.stringof);
}
return true;
}
return false;
}
...
As I'm not very good at D, I would like to get some feedback
about this solutions' viability. AFAIU memcpy-ing struct here is
safe because all target arguments ever passed to tryPutting are
internal to implementation(and SHOULD be void-initialized but
it's currently not working AFAIK). Maybe postblit should also be
called for new instance, but I'm not sure about current state of
qualified postblit.
Any help would be greatly appreciated!
More information about the Digitalmars-d-learn
mailing list