Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bslmf_resulttype
[Package bslmf]

Provide access to result_type or ResultType nested type. More...

Namespaces

namespace  bslmf

Detailed Description

Outline
Purpose:
Provide access to result_type or ResultType nested type.
Classes:
bslmf::ResultType metafunction to return result type
See also:
Description:
A number of functor classes provide a typedef alias for the returned type when invoking the functor. Unfortunately, standard types name this typedef result_type whereas BDE types name this typedef ResultType. This component facilitates writing code that depends on these typedefs by providing a uniform interface, bslmf::ResultType, for extracting the correct alias. bslmf::ResultType<t_FUNC>type is identical to t_FUNC::result_type if such a type exists; otherwise, it is identical to t_FUNC::ResultType if that type exists; otherwise, it is undefined. A fallback type can be optionally specified such that bslmf::ResultType<t_FUNC, t_FALLBACK>type is identical to t_FALLBACK if neither t_FUNC::result_type nor t_FUNC::ResultType is defined.
Note that ResultType checks only for a nested type within its t_FUNC parameter; it does not attempt to deduce the return type of calling operator() the way C++11 std::result_of does.
Usage:
In this section we show intended use of this component.
Usage Example 1:
In this example, we write a C++03-compatible function template, wrapInvoke<t_FUNC>(t_A1 a1, t_A2 a2), that constructs an instance of functor t_FUNC, invokes it with arguments a1 and a2, and translates any thrown exception to a generic exception type.
First, we declare the generic exception type:
  struct InvocationException { };
Now, we declare wrapInvoke. The return type of wrapInvoke should be the same as the return type of invoking an object of type t_FUNC. There is no non-intrusive way to deduce the return type of t_FUNC in C++03. We therefore require that t_FUNC provide either a result_type nested type (the idiom used in standard library functors) or a ResultType nested type (the idiom used in BDE library functors). We use bslmf::ResultType to automatically select the correct idiom:
  template <class t_FUNC, class t_A1, class t_A2>
  typename bslmf::ResultType<t_FUNC>::type
  wrapInvoke(t_A1 a1, t_A2 a2)
  {
      t_FUNC f;
      try {
          return f(a1, a2);                                         // RETURN
      }
      catch (...) {
          throw InvocationException();
      }
  }
Next, we declare a functor class that compares its arguments, returns the string "less" if a1 < a2, returns "greater" if a2 > a1, and throws an exception if neither is true. The return type of this functor is declared using the BDE-style ResultType nested type:
  struct LessGreater {
      typedef const char *ResultType;
      struct BadArgs { };  // exception class

      const char *operator()(long a1, long a2);
          // For the specified long integers 'a1' and 'a2', return the
          // null-terminated string "less" if 'a1 < a2' and "greater" if
          // 'a2 < a1'; otherwise, throw 'BadArgs()'.
  };

  const char *LessGreater::operator()(long a1, long a2)
  {
      if (a1 < a2) {
          return "less";                                            // RETURN
      }
      else if (a2 < a1) {
          return "greater";                                         // RETURN
      }
      else {
          throw BadArgs();
      }
  }
For comparison, let's also define a plus functor that conforms to the C++11 standard definition of std::plus:
  template <class TYPE>
  struct plus {
      typedef TYPE first_argument_type;
      typedef TYPE second_argument_type;
      typedef TYPE result_type;
      TYPE operator()(const TYPE& x, const TYPE& y) const { return x + y; }
  };
Now, we can use wrapInvoke with our LessGreater functor:
  int main()
  {
      const char *s = wrapInvoke<LessGreater>(5, -2);
      assert(0 == std::strcmp(s, "greater"));
Finally, we confirm that we can also use wrapInvoke with the functor plus<int>:
      int sum = wrapInvoke<plus<int> >(5, -2);
      assert(3 == sum);

      return 0;
  }
Usage Example 2:
This example extends the previous one by considering a functor that does not declare either result_type or ResultType. The PostIncrement functor performs the operation *a += b and returns the old value of *a:
  struct PostIncrement {
      int operator()(int *a, int b)
      {
          unsigned tmp = *a;
          *a += b;
          return tmp;
      }
  };
Unfortunately, the following innocent-looking code is ill-formed; even though the return value is being discarded, the return type of wrapInvoke is undefined because bslmf::ResultType<PostIncrement>type is undefined:
  // int x = 10;
  // wrapInvoke<PostIncrement>(x, 2);  // ill-formed
To make wrapInvoke usable in these situations, we define a new version, wrapInvoke2, that will fall back to a void return type if neither t_FUNC::result_type nor t_FUNC::ResultType is defined:
  template <class t_FUNC, class t_A1, class t_A2>
  typename bslmf::ResultType<t_FUNC, void>::type
  wrapInvoke2(t_A1 a1, t_A2 a2)
  {
      typedef typename bslmf::ResultType<t_FUNC, void>::type RetType;
      t_FUNC f;
      try {
          // C-style cast needed for some compilers
          return (RetType)f(a1, a2);                                // RETURN
      }
      catch (...) {
          throw InvocationException();
      }
  }
This use of the fallback parameter allows us to use bslmf::ResultType in a context where the return type of a function might be ignored:
  int main()
  {
      int x = 10;
      wrapInvoke2<PostIncrement>(&x, 2);
      assert(12 == x);
      return 0;
  }