BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslmf_resulttype

Detailed Description

Outline

Purpose

Provide access to result_type or ResultType nested type.

Classes

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>
wrapInvoke(t_A1 a1, t_A2 a2)
{
t_FUNC f;
try {
return f(a1, a2); // RETURN
}
catch (...) {
throw InvocationException();
}
}
t_FALLBACK type
Definition bslmf_resulttype.h:260

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>
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;
}