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