void foo();
static assert(is(ReturnType!(SymbolType!foo) == void));
int bar();
static assert(is(ReturnType!(SymbolType!bar) == int));
// ReturnType requires a type.
static assert(!__traits(compiles, ReturnType!bar));
// ReturnType requires a function type, function pointer type, or delegate
// type, so the result of PropertyType only works with it if the function
// returns such a type.
static assert(!__traits(compiles, ReturnType!(PropertyType!bar)));
string function(int) funcPtr;
static assert(is(ReturnType!(SymbolType!funcPtr) == string));
int delegate(string) del;
static assert(is(ReturnType!(SymbolType!del) == int));
int delegate(string) retDel();
static assert(is(ReturnType!(SymbolType!retDel) == int delegate(string)));
static assert(is(ReturnType!(PropertyType!retDel) == int));
static assert(is(ReturnType!(typeof(retDel)) == int delegate(string)));
@property int delegate(string) prop();
static assert(is(ReturnType!(SymbolType!prop) == int delegate(string)));
static assert(is(ReturnType!(PropertyType!prop) == int));
static assert(is(ReturnType!(typeof(prop)) == int));
ref int returnByRef();
static assert(is(ReturnType!(SymbolType!returnByRef) == int));
1 static struct S
2 {
3 void foo(string);
4 bool foo(string, int);
5 string foo();
6
7 @property void bar(int);
8 @property int bar();
9 }
10
11 // SymbolType gives the type of the first overload, whereas PropertyType
12 // gives the type of the overload which can be used as a getter property
13 // (or fails to compile if there is no such overload). Of course, the
14 // result of PropertyType won't compile with ReturnType unless the property
15 // gives a function pointer or delegate.
16 // __traits(getOverloads, ...) can be used to get specific overloads (or to
17 // iterate through all of them).
18 {
19 static assert( is(ReturnType!(SymbolType!(S.foo)) == void));
20 static assert( is(PropertyType!(S.foo) == string));
21
22 static assert( is(typeof(S.init.foo("")) == void));
23 static assert( is(typeof(S.init.foo("", 42)) == bool));
24 static assert( is(typeof(S.init.foo()) == string));
25
26 alias overloads = __traits(getOverloads, S, "foo");
27
28 // string foo();
29 static assert( is(ReturnType!(SymbolType!(overloads[0])) == void));
30
31 // void foo(string);
32 static assert( is(ReturnType!(SymbolType!(overloads[1])) == bool));
33
34 // void foo(string, int);
35 static assert( is(ReturnType!(SymbolType!(overloads[2])) == string));
36 }
37 {
38 static assert( is(ReturnType!(SymbolType!(S.bar)) == void));
39 static assert( is(PropertyType!(S.bar) == int));
40
41 // Normal function call syntax can be used with @property functions
42 // (which is obviously not the intended way to use them, but it does
43 // provide a way to distinguish between overloads).
44 static assert( is(typeof(S.init.bar(42)) == void));
45 static assert( is(typeof(S.init.bar()) == int));
46
47 static assert( is(typeof(S.init.bar = 42) == void));
48 static assert( is(PropertyType!(S.init.bar) == int));
49
50 alias overloads = __traits(getOverloads, S, "bar");
51
52 // @property void bar(int);
53 static assert( is(ReturnType!(SymbolType!(overloads[0])) == void));
54
55 // @property int bar();
56 static assert( is(ReturnType!(SymbolType!(overloads[1])) == int));
57 }
Evaluates to the return type of the given function type, function pointer type, or delegate type.
Note that $(K_REF) is an attribute / storage class, not part of the type. So, when the return type is marked with $(K_REF), $(K_REF) is an attribute of the function and not part of the return type. functionAttributes can be used to determine whether the return value is returned by $(K_REF).
Also note that in most cases, ReturnType is probably not the best solution.
In situations where a function is used as a getter property, then using PropertyType would usually make more sense than using ReturnType, particularly since in such a situation, the property could potentially be a variable, which would not compile with ReturnType.
In situations where a function may be overloaded, it can often make more sense to get the type of the expression where the function is called instead of getting the return type of the function itself - e.g. typeof(foo(42)) instead of ReturnType!(SymbolType!foo), since then that will automatically get the correct overload, whereas with ReturnType, getting the return type of the correct overload would require using __traits(getOverloads, foo) and then selecting the correct overload. Getting the type of the actual function call can also can be less verbose and require fewer template instantiations, since a function call is clearly an expression and thus avoids the need for SymbolType.
So, with functions which can be used as getter properties, it's often better to use PropertyType than to use ReturnType, and with functions which cannot be used as getter properties, it's often better to simply get the type of the actual function call. So, ReturnType is usually not the best choice, but there are of course situations where it's exactly what's needed (e.g. if code already has the symbol or type for a specific function overload and needs to get its return type).