1270. result_of should be moved to <type_traits>

Section: 99 [func.ret] Status: C++11 Submitter: Alisdair Meredith Opened: 2009-11-19 Last modified: 2016-01-28 10:19:27 UTC

Priority: Not Prioritized

View all other issues in [func.ret].

View all issues with C++11 status.


Addresses UK 198

NB Comment: UK-198 makes this request among others. It refers to a more detailed issue that BSI did not manage to submit by the CD1 ballot deadline though.

result_of is essentially a metafunction to return the type of an expression, and belongs with the other library metafunctions in <type_traits> rather than lurking in <functional>. The current definition in <functional> made sense when result_of was nothing more than a protocol to enable several components in <functional> to provide their own result types, but it has become a more general tool. For instance, result_of is now used in the threading and futures components.

Now that <type_traits> is a required header for free-standing implementations it will be much more noticeable (in such environments) that a particularly useful trait is missing, unless that implementation also chooses to offer <functional> as an extension.

The simplest proposal is to simply move the wording (editorial direction below) although a more consistent form for type_traits would reformat this as a table.

Following the acceptance of 1255, result_of now depends on the declval function template, tentatively provided in <utility> which is not (yet) required of a free-standing implementation.

This dependency is less of an issue when result_of continues to live in <functional>.

Personally, I would prefer to clean up the dependencies so both result_of and declval are available in a free-standing implementation, but that would require slightly more work than suggested here. A minimal tweak would be to require <utility> in a free-standing implementation, although there are a couple of subtle issues with make_pair, which uses reference_wrapper in its protocol and that is much harder to separate cleanly from <functional>.

An alternative would be to enact the other half of N2979 and create a new minimal header for the new C++0x library facilities to be added to the freestanding requirements (plus swap.)

I have a mild preference for the latter, although there are clearly reasons to consider better library support for free-standing in general, and adding the whole of <utility> could be considered a step in that direction. See NB comment JP-23 for other suggestions (array, ratio)

[ 2010-01-27 Beman updated wording. ]

The original wording is preserved here:

Move 99 [func.ret] to a heading below 21 [meta]. Note that in principle we should not change the tag, although this is a new tag for 0x. If it has been stable since TR1 it is clearly immutable though.

This wording should obviously adopt any other changes currently in (Tentatively) Ready status that touch this wording, such as 1255.

[ 2010-02-09 Moved to Tentatively Ready after 5 positive votes on c++std-lib. ]

Proposed resolution:

From Function objects 22.10 [function.objects], Header <functional> synopsis, remove:

// 20.7.4 result_of:
template <class> class result_of; // undefined
template <class F, class... Args> class result_of<F(ArgTypes...)>;

Remove Function object return types 99 [func.ret] in its entirety. This sub-section reads:

namespace std {
  template <class> class result_of; // undefined

  template <class Fn, class... ArgTypes>
  class result_of<Fn(ArgTypes...)> {
  public :
    // types
    typedef see below type;

Given an rvalue fn of type Fn and values t1, t2, ..., tN of types T1, T2, ..., TN in ArgTypes, respectively, the type member is the result type of the expression fn(t1, t2, ...,tN). The values ti are lvalues when the corresponding type Ti is an lvalue-reference type, and rvalues otherwise.

To Header <type_traits> synopsis 21.3.3 [meta.type.synop], add at the indicated location:

template <class T> struct underlying_type;
template <class T> struct result_of; // not defined
template <class Fn, class... ArgTypes> struct result_of<Fn(ArgTypes...)>;

To Other transformations [meta.trans.other], Table 51 — Other transformations, add:

Template Condition Comments
template <class T>
struct underlying_type;
T shall be an enumeration type (7.2) The member typedef type shall name the underlying type of T.
template <class Fn, class... ArgTypes> struct result_of<Fn(ArgTypes...)>; Fn shall be a function object type 22.10 [function.objects], reference to function, or reference to function object type. decltype(declval<Fn>()(declval<ArgTypes>()...)) shall be well formed. The member typedef type shall name the type decltype(declval<Fn>()(declval<ArgTypes>()...)).

At the end of Other transformations [meta.trans.other] add:

[Example: Given these definitions:

typedef bool(&PF1)();
typedef short(*PF2)(long);

struct S {
  operator PF2() const;
  double operator()(char, int&);

the following assertions will hold:

static_assert(std::is_same<std::result_of<S(int)>::type, short>::value, "Error!");
static_assert(std::is_same<std::result_of<S&(unsigned char, int&)>::type, double>::value, "Error!");
static_assert(std::is_same<std::result_of<PF1()>::type, bool>::value, "Error!");

 — end example]