13

I have:

class A {
public:
    B           toCPD() const;

And:

template<typename T>
class Ev {
public:
    typedef result_of(T::toCPD()) D;

After instantiating Ev<A>, the compiler says:

meta.h:12: error: 'T::toCPD' is not a type

neither decltype nor typeof work either.

Neil G
  • 32,138
  • 39
  • 156
  • 257
  • 2
    For general interest, it's worth noting that C++0x allows the same for nonstatic *data* members. You *can* do for example `struct A { int a; }; decltype(A::a * 3) b = 0;` already in GCC4.5. You can do anything with non-static data-members as long as it happens in an unevaluated operand in C++0x. – Johannes Schaub - litb May 04 '10 at 17:09

2 Answers2

34

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.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • There are no special member function types. The type of a member function is a normal function type. For instance member function pointers are member pointers to normal function types: `identity::type A::*` is equivalent to `void(A::*)()`. You cannot pass a member pointer type to `result_of`. In particular, `result_of<>::type` is specified as `decltype(declval()(declval()...))` with `Fn` being the function type/function-object type or reference to it passed. – Johannes Schaub - litb May 04 '10 at 17:06
  • GCC sometimes outputs the "type" `void(T::)()` or similar for a function of type `void()` in class `T`. But such a type does not exist - it's just implementation details bubbling up. – Johannes Schaub - litb May 04 '10 at 17:07
  • Actually, having had a closer look, it's more like `result_if` . So, `Fn` cannot be a function type (the type-id would specify a function returning a function). `Fn` has to be a reference to function or reference or direct type of a function object. And `Args` the arguments it's called with. – Johannes Schaub - litb May 04 '10 at 17:13
  • @litb: Thanks! It was hard to figure out what `result_of` is supposed to do because I can't find a single working case for GCC 4.5. Is it supposed to be possible to remove the pointer from a ptmf type and obtain a function type? If not, isn't that a hole in the library? It's easy enough to implement! – Potatoswatter May 04 '10 at 18:45
  • i can't seem to find a ready made standard template for that. As a work-around you could do `typedef typename result_of::type`, i think, but i think it's ugly :) – Johannes Schaub - litb May 04 '10 at 19:11
3

result_of is not a function neither an operator. result_of is a meta-function having a function as template parameter and setting the result type on the member type

typedef typename result_of<T::toCPD()>::type D;
Vicente Botet Escriba
  • 4,305
  • 1
  • 25
  • 39