On Tuesday, 17 March 2015 at 07:56:19 UTC, Ali Çehreli wrote:
> Why can't you do this instead?
>
> t opCast(t)()
> if (is(typeof(cast(T)this)))
> {
>      return cast(T)this;
> }

That has the same problem: 'cast(T)this' happens to be an explicit cast, which is disabled by the opCast overload for int.

Ali

For classes, `T opCast(T)() {return cast(T) super;}` may be viable.

For structs, it's seems more difficult to me.

`return this.to!T;` may try a cast(T), so it has the same problem as `return cast(T) this;`: infinite recursion. Example:
----
struct StdConvTo
{
    int* p;
    int opCast(T : int)() {return 42;}
    T opCast(T)() {import std.conv; return this.to!T;}
}
unittest
{
    assert((cast(int) StdConvTo()) == 42); /* ok */
auto i = cast(immutable StdConvTo) StdConvTo(); /* infinite recursion */
}
----
This applies to classes, too.

A reinterpret cast would allow casts that should be rejected:
----
struct Reinterpet
{
    int* p;
    int opCast(T : int)() {return 42;}
    T opCast(T)() {return * cast(T*) &this;}
}
unittest
{
    assert((cast(int) Reinterpet()) == 42); /* ok */
auto s = cast(float) Reinterpet(); /* compiles, but shouldn't */
}
----

Here's something that might work. Construct a "tuple" of the struct's fields (i.e. same data but no opCast). Then cast that to T.
----
struct TupleOf
{
    int* p;
    int opCast(T : int)() {return 42;}
    T opCast(T)()
    {
        static struct Tuple(S) {S stuff;}
        static Tuple!S tuple(S)(S stuff) {return Tuple!S(stuff);}
        return cast(T) tuple(this.tupleof);
    }
}
unittest
{
    assert((cast(int) TupleOf()) == 42); /* ok */
    auto i = cast(immutable TupleOf) TupleOf(); /* ok */
static assert(!__traits(compiles, cast(float) TupleOf())); /* ok */
}
----
This is probably not perfect either.

Reply via email to