On 02/11/2017 03:15 PM, Random D user wrote:
> I can init a variable from mutable source without defining any
> constructor or assignment operators, but not if the source is const. I
> would imagine the behavior to be the same with mutable and const source,
> since it's just reading the source and copying it.
>
> Is there a reason for this? Or is this a bug?
> I can workaround this by making copies or casting, that just creates
> ugly code everywhere.

Just to make sure, you don't need to define all those overloads. This is sufficient but you have to use a different (and idiomatic construction syntax.):

struct Foo
{
    this( const(Foo) source )
    {
        buf = source.buf.dup;
    }

    void opAssign( const(Foo) source )
    {
        buf = source.buf.dup;
    }

    char[] buf;
}

Foo fun(const ref Foo foo, Foo foo2)
{
    auto bar = Foo(foo);
// Foo bar = foo; // Error: cannot implicitly convert expression (foo) of type const(Foo) to Foo Foo baz = foo2; // Ok, No need for constructors or opAssign
    auto baz2 = const(Foo)(foo2);
    Foo bar2;
bar2 = foo; // uses opAssing( const Foo ) / opAssign( const ref Foo )
    Foo bar3;
bar3 = foo2; // uses opAssign( const Foo ) / opAssign( Foo )
    Foo bar4;
    bar4     = cast(const Foo)foo2;     // uses opAssing( const Foo )

//Foo bar = Foo(foo); // This works provided there is non-const opAssign defined.
    //Foo bar = cast(Foo)foo; // This seems to work as well
    return bar;
}

void main() {
}

When you do this:

    Foo bar = foo;

There is an implicit conversion in place, which D does not allow during construction. The idiomatic syntax is the following:

    auto bar = Foo(foo);

The construction on the right-hand side is now explicit.

Likewise, prefer the following syntax:

    auto baz2 = const(Foo)(foo2);

Notes:

When you want to treat lvalue sources differently from rvalue sources, you can define the following overloads as well (note const(Foo) syntax, which is preferred):

    this( ref const(Foo) source )
    {
        buf = source.buf.dup;
    }

    void opAssign( ref const(Foo) source )
    {
        buf = source.buf.dup;
    }

Alternatively, you can define an 'auto ref' function that automatically takes both lvalues and rvalues (lvalue by-ref, rvalues by-move). Note the empty template parentheses:

struct Foo
{
    this()( auto ref const(Foo) source )
    {
        buf = source.buf.dup;
    }

    void opAssign()( auto ref const(Foo) source )
    {
        buf = source.buf.dup;
    }

    char[] buf;
}

Ali

Reply via email to