Unifying TR1 Function Object Type Specifications

Document number:   N1673=04-0113
Date:   September 10, 2004
Project:   Programming Language C++
Reference:   ISO/IEC IS 14882:2003(E)
Reply to:   Pete Becker
  Dinkumware, Ltd.
  petebecker@acm.org
  Peter Dimov
  pdimov@mmltd.net


Introduction · Framework Overview · Summary of Proposed Changes · Open Issues · Proposed Changes


Introduction

Technical Report 1 introduces four templates for types whose instances can act as function objects. These templates were written by various people at various times and with somewhat different goals. They have much in common, however, and their specifications can be simplified by providing a set of shared definitions that support a uniform conceptual framework. This paper defines such a framework and applies it to the TR1 specifications for reference_wrapper, function, mem_fn, and bind.

Framework Overview

Roughly speaking, TR1 defines templates for creating function objects that, when called, forward to other function objects. That formulation is muddled, however, because the two uses of the term "function objects" mean two somewhat different things. We introduce several technical terms to provide a more precise vocabulary:

TR1 provides four different kinds of call wrappers: objects of type reference_wrapper<T> where T is a callable type; objects of type function<F>; objects returned by calls to the template function mem_fn; and objects returned by calls to the template function bind.

Summary of Proposed Changes

The proposed changes add the framework sketched above to TR1 and rewrite the specifications of reference_wrapper, function, mem_fn, and bind in terms of that framework. Most of the changes are intended to change only the way that the specification is expressed. A few changes, however, are changes in the requirements. These changes are:

Open Issues

For easier presentation, some of the proposed changes assume particular resolutions to open TR issues, as listed below. In this paper we take no position on how these issues should be resolved.

Proposed Changes

Overall changes

Add a new subclause, "Definitions", to the beginning of [tr.func]:

The following definitions shall apply to this clause:
A call signature is the name of a return type followed by a parenthesized comma-separated list of zero or more argument types.
A call wrapper is an object of a call wrapper type.
A call wrapper type is a type that holds a callable object and supports a call operation that forwards to that object.
A callable object is an object of a callable type.
A callable type is a pointer to function, a pointer to member function, a pointer to member data, or a class type whose objects can appear immediately to the left of a function call operator.
A target object is the callable object held by a call wrapper object.

Add a new subclause, "Requirements", after [tr.func.syn]:

Define INVOKE(f, t1, t2, ..., tN) as follows:
Define INVOKE(f, t1, t2, ..., tN, R) as INVOKE(f, t1, t2, ..., tN) implicitly converted to R.
If a call wrapper has a weak result type the type of its member type result_type is based on the type T of the wrapper's target object:
Every call wrapper shall be CopyConstructible. A simple call wrapper is a call wrapper that is Assignable and whose copy constructor and assignment operator do not throw exceptions. A forwarding call wrapper is a call wrapper that can be called with an argument list t1, t2, ..., tN where each ti is an lvalue. The effect of calling a forwarding call wrapper with one or more arguments that are rvalues is implementation defined. [Note: in a typical implementation forwarding call wrappers have overloaded function call operators of the form
    template<class T1, class T2, ..., class TN>
    R operator()(T1& t1, T2& t2, ..., TN& tN) cv-qual;
-- end note]

Changes to reference_wrapper

In [tr.util.refwrp.refwrp], remove paragraph 2 and its three bullet items and replace them with:

reference_wrapper has a weak result type.

Remove both paragraphs of [tr.util.refwrp.invoke] and replace them with:

Returns: INVOKE(get(), a1, a2, ..., aN)

Changes to function

Remove paragraphs 1, 2, and 3 from [tr.func.wrap.func].

After the template definition in [tr.func.wrap.func] add the following:

The function class template provides polymorphic wrappers that generalize the notion of a function pointer. Wrappers can store, copy, and call arbitrary callable objects, given a call signature, allowing functions to be first-class objects.
A function object f of type F is Callable for argument types T1, T2, ..., TN and a return type R, if, given lvalues t1, t2, ..., tN of types T1, T2, ..., TN, respectively, INVOKE(f, t1, t2, ..., tN) is well-formed and, if R is not void, convertible to R.
The function class template is a call wrapper whose call signature is R(T1, T2, ..., TN).

Remove paragraphs 1 and 2 of [tr.func.wrap.func.inv] and replace them with:

Effects: INVOKE(f, t1, t2, ..., tN, R), where f is the target object of *this.
Returns: nothing, if R is void, otherwise the return value of INVOKE(f, t1, t2, ..., tN, R).

Changes to mem_fn

Replace [tr.func.memfn] with:

    template<class R, class T>
    unspecified mem_fn(R T::*pm);
Returns: a simple call wrapper f such that the expression f(t, a2, ..., aN) is equivalent to INVOKE(pm, t, a2, ..., aN). f shall have a nested type result_type that is a synonym for the return type of pm when pm is a pointer to member function, or a synonym for R or for R const& otherwise3.
Throws: nothing.
Notes: implementations may implement mem_fn as a set of overloaded function templates.

Changes to bind

Replace [tr.func.bind.bind] with:

    template<class F, class T1, class T2, ...., class TN>
    unspecified bind(F f, T1 t1, T2 t2, ..., TN tN);

Requires:  F and Ti shall be CopyConstructible. INVOKE(f, w1, w2, ..., wN) shall be a valid expression for some values w1, w2, ..., wN.

Returns: A forwarding call wrapper g with a weak result type. The effect of g(u1, u2, ..., uM) shall be INVOKE(f, v1, v2, ..., vN, result_of<F cv (V1, V2, ..., VN)>::type), where cv are the cv-qualifiers of g and the values and types of the bound arguments v1, v2, ..., vN are determined as specified below.

    template<class R, class F, class T1, class T2, ...., class TN>
    unspecified bind(F f, T1 t1, T2 t2, ..., TN tN);

Requires:  F and Ti shall be CopyConstructible. INVOKE(f, w1, w2, ..., wN) shall be a valid expression for some values w1, w2, ..., wN.

Returns: A forwarding call wrapper g with a nested type result_type defined as a synonym for R. The effect of g(u1, u2, ..., uM) shall be INVOKE(f, v1, v2, ..., vN, R), where the values and types of the bound arguments v1, v2, ..., vN are determined as specified below.

The values of the bound arguments v1, v2, ..., vN and their corresponding types V1, V2, ..., VN depend on the type of the corresponding argument ti of type Ti in the call to bind and the cv-qualifiers cv of the call wrapper g as follows:

Changes to Implementation quantities

Change the title of [tr.limits] to:

Annex A (informative) Implementation quantities

Change the text of [tr.limits] to the following:

Nmax, the maximum number of arguments that can be forwarded by the call wrappers defined in [tr.util.refwrap], [tr.func.memfn], [tr.func.bin], [tr.func.wrap], and the maximum number of argument types that can be passed in the argument to result_of ([tr.func.ret]), is implementation defined. The value of Nmax should be at least 10.
The number of distinct placeholders is implementation defined. The number should be at least 10.
The maximum number of elements in one tuple type (clause [tr.tuple]) is implementation defined. The value should be at least 10.

1. A pointer to member data cannot, of course, be "called" in the usual sense.

2. Such a type often has a member operator(), but in some cases it can omit that member and provide a conversion to a pointer to function.

3. This requirement should be changed to reflect the resolution of issue 10.24. (This footnote is not intended to be part of TR1)


Portions of this document are derived from work copyright © 2004 by Dinkumware, Ltd. All such material is made available for standardization purposes only, and its inclusion does not waive the rights of Dinkumware, Ltd. under applicable copyright laws.