18 Sep 2008 redi   » (Master)

result_of

Some ramblings about result_of, a little utility available from Boost. It was proposed for standardisation in n1454, was included in TR1, and will be in C++0x. It's used inside some other Boost libraries, but many C++ programmers will never need to use it directly, or know any of what follows. If you do need to know about it, there's a much better description in Pete Becker's book.

The syntax, e.g. result_of<Func(Arg1*, Arg2&)>::type may not obvious at first glance, even if you know C++ fairly well. Result_of is a unary metafunction, a template with one parameter:

  
template<typename Signature>
  struct result_of;

There is no definition for the primary template, only for partial specializations where the template parameter is a function type:
  
template<typename Fn, typename... ArgTypes>
  struct result_of<Fn(ArgTypes...)>
  {
    typedef ??? type;
  };

The specialization contains a typedef, type. In the earlier example, the function type used as the template argument to result_of is Func(Arg1*, Arg2&)

That type is a function taking a pointer to Arg1 and an lvalue-reference to Arg2, and returning Func. Compare it to the more familiar declaration of a pointer to such a function:

Func (*)(Arg1*, Arg2&)

This doesn't mean there is a function taking those arguments and returning Func, it's just a made-up type passed to result_of, which extracts the necessary information from the type using a bit of template metaprogramming from the school of Boost. The function-type syntax is used to mimic the syntax of invoking some callable type, Func, with arguments of those types, as in

Func func;
Arg1 arg1;
Arg2 arg2;
func(&arg1, arg2); // compare with Func(Arg1*,Arg2&);

So result_of<Func(Arg1*,Arg2&)>::type is a typedef for the return type of the call above, which due to overloading and implicit conversions could be pretty much anything!

  
// type is int if Func is:
typedef int (*Func)(Arg1*,const Arg&);
// type is char if Func is:
struct Func {
  void operator()(int);
  char operator()(void*, Arg2) const;
};
// type is double given:
struct Base { };
struct Arg1 : Base { };
struct Arg2 : Base { };
struct Functor {
    int operator()(Arg1*, Arg2&);
    double operator()(Base*, Base&, Base* = 0) const;
};
typedef const Functor Func;

In the last example the first operator, which matches the argument types exactly, is not const, so cannot be called on a const Functor, so the second operator is chosen, converting the arguments and using the default for the third argument. Getting result_of to give the right answer was a fun little exercise.

Latest blog entries     Older blog entries

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!