views:

136

answers:

2

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.

+3  A: 

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
It is never valid to call a function inside a template argument.
Potatoswatter
It looks like decltype should have worked though. Unless of course it's not supported in the OP's compiler
jalf
What's the header for result_of?
Sumant
@jalf: `decltype` didn't work because he attemped to call a nonstatic function using `::`. See my answer.
Potatoswatter
@Potatoswatter: ah right, guess I should have actually read the code properly. ;)
jalf
+5  A: 

Since whatever result you obtain depends on the template parameter, typedef typename is necessary.

decltype is a C++0x extension which isn't yet fully supported by GCC. 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 takes a type and returns a meaningless, unconstructed value of that type.

typedef typename decltype( declval<T>().toCPD() ) D; // YUCK!

typeof is a nonstandard, older alias for decltype. Here is its documentation under GCC.


result_of is a TR1 extension which should be more portable, but doesn't seem to work at all in GCC 4.2.1 and 4.5. It is a template which takes a function type (such as int(void) or int(*)(void)) and returns that function's return type.

Unfortunately, it is not specified to work with pointer-to-member-function (ptmf) types. Furthermore, although non-pointer member function objects (i.e. a hypothetical T::toCPD with no &) have the type of regular functions (thanks to Litb for the tip), there is no way to name such an object in C++03 at least, and I'm not aware of any way to form such a type from a ptmf type in C++03 or TR1. std::remove_ptr in C++0x might be capable of such, but it's unclear from the spec and doesn't work in GCC 4.5.

Even if you do have a non-member function, a template can't resolve the type (B ()) of an object (B foo()). Only decltype can do that (or function template type deduction, which we can't use here).

Maybe there is a way to use result_of in such a way as to remove the need for declval, but I can't find it.


On the other hand, it's quite easy to write result_of_ptmf for ptmf types:

template< class T >
struct result_of_ptmf {};

template< class R, class C, class ... A >
struct result_of_ptmf< R (C::*)( A ... ) > {
    typedef R type;
};

(in C++0x anyway) and use it:

typedef typename result_of_ptmf< decltype( &T::toCPD ) >::type D;

This works fine in GCC 4.5.

Potatoswatter
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<void()>::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<Fn>()(declval<ArgTypes>()...))` with `Fn` being the function type/function-object type or reference to it passed.
Johannes Schaub - litb
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
Actually, having had a closer look, it's more like `result_if<Fn(Args)>` . 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
@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
Johannes Schaub - litb