Where does "U" in Rebindable.Rebindable come from?
Simen Kjærås
simen.kjaras at gmail.com
Fri Mar 30 08:13:25 PDT 2012
On Fri, 30 Mar 2012 15:03:49 +0200, simendsjo <simendsjo at gmail.com> wrote:
> On Fri, 30 Mar 2012 01:09:06 +0200, Simen Kjærås
> <simen.kjaras at gmail.com> wrote:
>
>> On Thu, 29 Mar 2012 22:15:41 +0200, simendsjo <simendsjo at gmail.com>
>> wrote:
>>
>>> If you look at the struct, it uses the type U in, among others, the
>>> union.
>>>
>>> The only place I could see U referenced is in the first static if, but
>>> I cannot recreate this behavior:
>>> void main() {
>>> static if(is(int X == const(U), U))
>>
>> Ah, the magic of isExpressions...
>>
>> What happens here is the isExpression asks 'if X is an int, does it
>> match the pattern const(U), where U is some type?'
>>
>> Of course, there is no U for which const(U) == int, so the isExpresion
>> returns false, and your static assert triggers.
>>
>>
>>> static if (!is(T X == const(U), U) && !is(T X == immutable(U), U))
>>
>> Again, 'is there a U such that const(U) == T?', then the same for
>> immutable(U). In other words - 'is T mutable?'.
>>
>> The reason the U is there is to explain to the compiler that we're
>> talking about this specific U, not some other U that may be defined
>> elsewhere in the program.
>>
>> The same pattern is used in std.typecons.isTuple:
>>
>> template isTuple(T)
>> {
>> static if (is(Unqual!T Unused : Tuple!Specs, Specs...))
>> {
>> enum isTuple = true;
>> }
>> else
>> {
>> enum isTuple = false;
>> }
>> }
>>
>> It can also be extended to other templates:
>>
>> struct Foo() {}
>> struct Foo(int n) {}
>> struct Foo(T) {}
>>
>> template FooType(T) {
>> static if (is(Unqual!T Unused : Foo!())) {
>> enum FooType = "Type 1";
>> } else static if (is(Unqual!T Unused : Foo!n, int n)) {
>> enum FooType = "Type 2";
>> } else static if (is(Unqual!T Unused : Foo!U, U)) {
>> enum FooType = "Type 3";
>> } else {
>> enum FooType = "No Foo!";
>> }
>> }
>>
>>
>> Hope this helps.
>
> Look at the Rebindable example again. What I don't understand is how U
> can be defined in the else block.
> Like your example here. "Unused" isn't defined in the else block,
> right..?
Indeed. The thing is - U is basically *set* by the isExpression. It says
'yes, there is such a U, so I'll add it to the local scope.'. This means
that U will be set for the entire scope within which the static if
exists.
Due to the way the criteria are phrased, U is defined when the criteria
are not met, and as such are defined in the else clause instead of the
if clause.
{ // Outer scope starts here.
static if ( !is( const(int) t == const(U), U ) ) {
// isExpression returned false, so U is undefined
} else {
// But here it is defined, because we're still in the same,
// broader scope.
}
}
// And here it's no longer defined.
Was that any better? I admit I didn't understand it at first either, but
then I remembered that static if does not introduce a new scope. That
helped.
More information about the Digitalmars-d-learn
mailing list