Since whatever result you obtain depends on the template parameter, typedef typename
is necessary.
decltype
is a standard C++11 feature. It is an "operator" which takes an expression and returns a type.
typedef typename decltype( T().toCPD() ) D; // can't use T:: as it's nonstatic
If T()
isn't a valid (T
not default-constructible) you will want declval
which is a function that takes a type and returns a meaningless, invalid value of that type. declval
can only be used in unevaluated contexts such as decltype
.
typedef typename decltype( std::declval<T>().toCPD() ) D;
Before C++11, decltype
was a non-standard extension by Microsoft's MSVC compiler. Its behavior might have been changed slightly by standardization.
typeof
is GCC's equivalent pre-C++11 extension like decltype
, which was also cloned in other compilers. Here is its documentation from GCC. That page provides no comparison between the features, but it notes that typeof
must be called __typeof__
when using a standard mode (-std=c++YY
, which you should always do), and it is available in C as well as C++.
For the sake of C compatibility, __typeof__
will not resolve a reference type from a glvalue expression. So, it's really only suitable for C. This probably explains why the C++ feature didn't inherit the more self-explanatory name: GNU was unwilling to sacrifice backward compatibility, whereas Microsoft cares less about C and perhaps needed fewer changes.
result_of
is a C++11 metafunction (previously standardized in the ISO TR1 library from 2006). It is a template which takes a callable type (such as a function int(void)
, function pointer int(*)(void)
, functor class implementing operator()
, or pointer-to-member-function &T::toCPD
) and an argument type-list for that type, and provides the return type if the call would work.
To use result_of
with a pointer to member function, you must include the parent object type in the argument list as a surrogate for this
.
typedef typename std::result_of< decltype( & T::toCPD ) ( T * ) >::type D;
This is very brittle, though, because &T::toCPD
cannot be resolved if there's any overloading, such as a non-const version. This is true despite the fact that T *
or T const *
must be explicitly written out! In most cases, you're better off with decltype
and declval
.