|
77 | 77 | $(LREF isFunction) |
78 | 78 | $(LREF isFunctionPointer) |
79 | 79 | $(LREF isReturn) |
| 80 | + $(LREF ReturnType) |
80 | 81 | $(LREF ToFunctionType) |
81 | 82 | )) |
82 | 83 | $(TR $(TD Aggregate Type Traits) $(TD |
@@ -3275,6 +3276,212 @@ enum isReturn(T) = is(T == return); |
3275 | 3276 | static assert( is(typeof(&S.init.foo) == return)); |
3276 | 3277 | } |
3277 | 3278 |
|
| 3279 | +/++ |
| 3280 | + Evaluates to the return type of the given function type, function pointer |
| 3281 | + type, or delegate type. |
| 3282 | +
|
| 3283 | + Note that $(K_REF) is an attribute / storage class, not part of the type. |
| 3284 | + So, when the return type is marked with $(K_REF), $(K_REF) is an attribute |
| 3285 | + of the function and not part of the return type. $(LREF functionAttributes) |
| 3286 | + can be used to determine whether the return value is returned by $(K_REF). |
| 3287 | +
|
| 3288 | + Also note that in most cases, ReturnType is probably not the best solution. |
| 3289 | +
|
| 3290 | + In situations where a function is used as a getter property, then using |
| 3291 | + $(LREF PropertyType) would usually make more sense than using ReturnType, |
| 3292 | + particularly since in such a situation, the property could potentially be a |
| 3293 | + variable, which would not compile with ReturnType. |
| 3294 | +
|
| 3295 | + In situations where a function may be overloaded, it can often make more |
| 3296 | + sense to get the type of the expression where the function is called |
| 3297 | + instead of getting the return type of the function itself - e.g. |
| 3298 | + $(D typeof(foo(42))) instead of $(D ReturnType!(SymbolType!foo)), since |
| 3299 | + then that will automatically get the correct overload, whereas with |
| 3300 | + ReturnType, getting the return type of the correct overload would require |
| 3301 | + using $(D __traits(getOverloads, foo)) and then selecting the correct |
| 3302 | + overload. Getting the type of the actual function call can also can be less |
| 3303 | + verbose and require fewer template instantiations, since a function call is |
| 3304 | + clearly an expression and thus avoids the need for $(LREF SymbolType). |
| 3305 | +
|
| 3306 | + So, with functions which can be used as getter properties, it's often |
| 3307 | + better to use $(LREF PropertyType) than to use ReturnType, and with |
| 3308 | + functions which cannot be used as getter properties, it's often better to |
| 3309 | + simply get the type of the actual function call. So, ReturnType is |
| 3310 | + usually not the best choice, but there are of course situations where it's |
| 3311 | + exactly what's needed (e.g. if code already has the symbol or type for a |
| 3312 | + specific function overload and needs to get its return type). |
| 3313 | +
|
| 3314 | + See_Also: |
| 3315 | + $(LREF functionAttributes) |
| 3316 | + $(LREF PropertyType) |
| 3317 | + $(LREF SymbolType) |
| 3318 | + +/ |
| 3319 | +template ReturnType(T) |
| 3320 | +if (is(T == return)) |
| 3321 | +{ |
| 3322 | + static if (is(T R == return)) |
| 3323 | + alias ReturnType = R; |
| 3324 | + else |
| 3325 | + static assert(false, "Somehow, ReturnType was instantiated with a type which has no return type"); |
| 3326 | +} |
| 3327 | + |
| 3328 | +/// |
| 3329 | +@safe unittest |
| 3330 | +{ |
| 3331 | + void foo(); |
| 3332 | + static assert(is(ReturnType!(SymbolType!foo) == void)); |
| 3333 | + |
| 3334 | + int bar(); |
| 3335 | + static assert(is(ReturnType!(SymbolType!bar) == int)); |
| 3336 | + |
| 3337 | + // ReturnType requires a type. |
| 3338 | + static assert(!__traits(compiles, ReturnType!bar)); |
| 3339 | + |
| 3340 | + // ReturnType requires a function type, function pointer type, or delegate |
| 3341 | + // type, so the result of PropertyType only works with it if the function |
| 3342 | + // returns such a type. |
| 3343 | + static assert(!__traits(compiles, ReturnType!(PropertyType!bar))); |
| 3344 | + |
| 3345 | + string function(int) funcPtr; |
| 3346 | + static assert(is(ReturnType!(SymbolType!funcPtr) == string)); |
| 3347 | + |
| 3348 | + int delegate(string) del; |
| 3349 | + static assert(is(ReturnType!(SymbolType!del) == int)); |
| 3350 | + |
| 3351 | + int delegate(string) retDel(); |
| 3352 | + static assert(is(ReturnType!(SymbolType!retDel) == int delegate(string))); |
| 3353 | + static assert(is(ReturnType!(PropertyType!retDel) == int)); |
| 3354 | + static assert(is(ReturnType!(typeof(retDel)) == int delegate(string))); |
| 3355 | + |
| 3356 | + @property int delegate(string) prop(); |
| 3357 | + static assert(is(ReturnType!(SymbolType!prop) == int delegate(string))); |
| 3358 | + static assert(is(ReturnType!(PropertyType!prop) == int)); |
| 3359 | + static assert(is(ReturnType!(typeof(prop)) == int)); |
| 3360 | + |
| 3361 | + ref int returnByRef(); |
| 3362 | + static assert(is(ReturnType!(SymbolType!returnByRef) == int)); |
| 3363 | +} |
| 3364 | + |
| 3365 | +/// |
| 3366 | +@safe unittest |
| 3367 | +{ |
| 3368 | + static struct S |
| 3369 | + { |
| 3370 | + void foo(string); |
| 3371 | + bool foo(string, int); |
| 3372 | + string foo(); |
| 3373 | + |
| 3374 | + @property void bar(int); |
| 3375 | + @property int bar(); |
| 3376 | + } |
| 3377 | + |
| 3378 | + // SymbolType gives the type of the first overload, whereas PropertyType |
| 3379 | + // gives the type of the overload which can be used as a getter property |
| 3380 | + // (or fails to compile if there is no such overload). Of course, the |
| 3381 | + // result of PropertyType won't compile with ReturnType unless the property |
| 3382 | + // gives a function pointer or delegate. |
| 3383 | + // __traits(getOverloads, ...) can be used to get specific overloads (or to |
| 3384 | + // iterate through all of them). |
| 3385 | + { |
| 3386 | + static assert( is(ReturnType!(SymbolType!(S.foo)) == void)); |
| 3387 | + static assert( is(PropertyType!(S.foo) == string)); |
| 3388 | + |
| 3389 | + static assert( is(typeof(S.init.foo("")) == void)); |
| 3390 | + static assert( is(typeof(S.init.foo("", 42)) == bool)); |
| 3391 | + static assert( is(typeof(S.init.foo()) == string)); |
| 3392 | + |
| 3393 | + alias overloads = __traits(getOverloads, S, "foo"); |
| 3394 | + |
| 3395 | + // string foo(); |
| 3396 | + static assert( is(ReturnType!(SymbolType!(overloads[0])) == void)); |
| 3397 | + |
| 3398 | + // void foo(string); |
| 3399 | + static assert( is(ReturnType!(SymbolType!(overloads[1])) == bool)); |
| 3400 | + |
| 3401 | + // void foo(string, int); |
| 3402 | + static assert( is(ReturnType!(SymbolType!(overloads[2])) == string)); |
| 3403 | + } |
| 3404 | + { |
| 3405 | + static assert( is(ReturnType!(SymbolType!(S.bar)) == void)); |
| 3406 | + static assert( is(PropertyType!(S.bar) == int)); |
| 3407 | + |
| 3408 | + // Normal function call syntax can be used with @property functions |
| 3409 | + // (which is obviously not the intended way to use them, but it does |
| 3410 | + // provide a way to distinguish between overloads). |
| 3411 | + static assert( is(typeof(S.init.bar(42)) == void)); |
| 3412 | + static assert( is(typeof(S.init.bar()) == int)); |
| 3413 | + |
| 3414 | + static assert( is(typeof(S.init.bar = 42) == void)); |
| 3415 | + static assert( is(PropertyType!(S.init.bar) == int)); |
| 3416 | + |
| 3417 | + alias overloads = __traits(getOverloads, S, "bar"); |
| 3418 | + |
| 3419 | + // @property void bar(int); |
| 3420 | + static assert( is(ReturnType!(SymbolType!(overloads[0])) == void)); |
| 3421 | + |
| 3422 | + // @property int bar(); |
| 3423 | + static assert( is(ReturnType!(SymbolType!(overloads[1])) == int)); |
| 3424 | + } |
| 3425 | +} |
| 3426 | + |
| 3427 | +@safe unittest |
| 3428 | +{ |
| 3429 | + int func1(string); |
| 3430 | + static assert(is(ReturnType!(SymbolType!func1) == int)); |
| 3431 | + static assert(!__traits(compiles, ReturnType!func1)); |
| 3432 | + |
| 3433 | + const(int) func2(string); |
| 3434 | + static assert(is(ReturnType!(SymbolType!func2) == const int)); |
| 3435 | + |
| 3436 | + immutable(int) func3(string); |
| 3437 | + static assert(is(ReturnType!(SymbolType!func3) == immutable int)); |
| 3438 | + |
| 3439 | + shared(int) func4(string); |
| 3440 | + static assert(is(ReturnType!(SymbolType!func4) == shared int)); |
| 3441 | + |
| 3442 | + const(shared(int)) func5(string); |
| 3443 | + static assert(is(ReturnType!(SymbolType!func5) == const shared int)); |
| 3444 | + |
| 3445 | + ref int func6(string); |
| 3446 | + static assert(is(ReturnType!(SymbolType!func6) == int)); |
| 3447 | + |
| 3448 | + ref const(int) func7(string); |
| 3449 | + static assert(is(ReturnType!(SymbolType!func7) == const int)); |
| 3450 | + |
| 3451 | + static struct S |
| 3452 | + { |
| 3453 | + real foo(); |
| 3454 | + real bar() const; |
| 3455 | + inout(real) baz() inout; |
| 3456 | + ref real func() shared; |
| 3457 | + } |
| 3458 | + static assert(is(ReturnType!(SymbolType!(S.foo)) == real)); |
| 3459 | + static assert(is(ReturnType!(SymbolType!(S.bar)) == real)); |
| 3460 | + static assert(is(ReturnType!(SymbolType!(S.baz)) == inout real)); |
| 3461 | + static assert(is(ReturnType!(SymbolType!(S.func)) == real)); |
| 3462 | + |
| 3463 | + static class C |
| 3464 | + { |
| 3465 | + byte foo() { assert(0); } |
| 3466 | + byte bar() const { assert(0); } |
| 3467 | + inout(byte) baz() inout { assert(0); } |
| 3468 | + ref byte func() shared { assert(0); } |
| 3469 | + } |
| 3470 | + static assert(is(ReturnType!(SymbolType!(C.foo)) == byte)); |
| 3471 | + static assert(is(ReturnType!(SymbolType!(C.bar)) == byte)); |
| 3472 | + static assert(is(ReturnType!(SymbolType!(C.baz)) == inout byte)); |
| 3473 | + static assert(is(ReturnType!(SymbolType!(C.func)) == byte)); |
| 3474 | + |
| 3475 | + static struct NoCopy |
| 3476 | + { |
| 3477 | + @disable this(this); |
| 3478 | + } |
| 3479 | + static assert(!__traits(isCopyable, NoCopy)); |
| 3480 | + |
| 3481 | + NoCopy retNC(); |
| 3482 | + static assert(is(ReturnType!(SymbolType!retNC) == NoCopy)); |
| 3483 | +} |
| 3484 | + |
3278 | 3485 | /++ |
3279 | 3486 | Converts a function type, function pointer type, or delegate type to the |
3280 | 3487 | corresponding function type. |
|
0 commit comments