no size yet for forward reference for nested structures

Steven Schveighoffer via Digitalmars-d digitalmars-d at puremagic.com
Thu Jan 15 05:19:32 PST 2015


On 1/14/15 10:09 AM, Ali Çehreli wrote:
> On 01/14/2015 02:53 AM, ketmar via Digitalmars-d wrote:
>
>  > On Wed, 14 Jan 2015 10:41:07 +0000
>  > qqiang via Digitalmars-d <digitalmars-d at puremagic.com> wrote:
>  >
>  >> template PowerHeap(T) {
>  >>       import std.container : SList;
>  >>
>  >>       private alias PowerForest = SList!PowerNode;
>  >>
>  >>       private final class PowerNode {
>  >>           private {
>  >>               T payload_;
>  >>               uint rank_;
>  >>               PowerForest children_;
>  >>           }
>  >>       }
>  >>
>  >>       final class PowerHeap {
>  >>           private {
>  >>               PowerNode top_;
>  >>               PowerForest forest_;
>  >>               uint size_;
>  >>           }
>  >>       }
>  >> }
>  >>
>  >> unittest {
>  >>       PowerHeap!int h;
>  >> }
>  > there is a circular dependency in your data structures. you're defining
>  > `PowerNode` in the terms of... `PowerNode`. this won't work.
>  >
>  > your `PowerForest` definition depends of complete `PowerNode`
>  > definition, but `PowerNode` definition depends of complete
>  > `PowerForest` definition.
>  >
>  > don't do that.
>  >
>
> Reduced:
>
> import std.container;
>
> class Node
> {
>      SList!Node children;
> }
>
> void main()
> {}
>
> Error: class deneme.Node no size yet for forward reference
>
> I wonder why an SList of a reference type requires the size of the
> elements? The following compiles but is that a pointer to a class
> variable or a class object? How can we even use the 'children' member?
>
>      SList!(Node*) children;
>
> Ali
>

In my not-so-expert opinion, I think this is somewhat of a bug, but not 
in the compiler. Note that it depends heavily on the definition of 
SList. If SList starts using pieces of S, it may confuse or create 
issues with the compiler.

A simple test is to declare an opaque class:

class S;

void main()
{
    S foo;
}

This works (at least it works to compile, not to link as the linker 
can't find the class symbol)

Now, if I do this:

import std.container;

class S;

alias listofs = SList!S;

void main()
{
    S foo;
}

I get the following audit from the compiler:

/usr/share/dmd/src/phobos/std/traits.d(2032): Error: class testforward.S 
unknown size
/usr/share/dmd/src/phobos/std/traits.d(2198): Error: template instance 
std.traits.FieldTypeTuple!(S) error instantiating
/usr/share/dmd/src/phobos/std/traits.d(2349):        instantiated from 
here: RepresentationTypeTuple!(S)
/usr/share/dmd/src/phobos/std/traits.d(2692):        instantiated from 
here: hasRawAliasing!(S)
/usr/share/dmd/src/phobos/std/algorithm.d(1888):        instantiated 
from here: hasAliasing!(S)
/usr/share/dmd/src/phobos/std/container.d(1008): Error: template 
instance std.algorithm.move!(S) error instantiating
testforward.d(4):        instantiated from here: SList!(S)
/usr/share/dmd/src/phobos/std/range.d(3149): Error: template instance 
std.range.hasAssignableElements!(Range) error instantiating
/usr/share/dmd/src/phobos/std/container.d(1359): Error: template 
instance std.range.Take!(Range) error instantiating
testforward.d(4):        instantiated from here: SList!(S)


So I think it's SList's invocation of move, which in turn checks 
hasAliasing, which in turn needs S's total definition (as it starts 
getting the fields of S). I think hasAliasing!(someclass) needs to be 
short circuited to true, or slist needs to use some other mechanism. I 
don't know how SList works exactly, maybe it does not actually allocate 
a list of class references, but instead emplaces them. In that case, you 
may be out of luck.

-Steve


More information about the Digitalmars-d mailing list