Document number: N1694=04-0134
Programming Language C++, Evolution Working Group
 
Peter Dimov <pdimov@mmltd.net>
 
September 06, 2004

A Proposal to Extend the Function Call Operator

Introduction

In a function call expression of the form E(a1, ..., aN), where the expression E evaluates to an object of class type (13.3.1.1.2, [over.call.object]), E's conversion operators are only considered if they can convert E to a pointer or reference to function.

An important design principle of C++ is that user-defined types should be given equal standing, wherever possible. In an application of this principle, this paper proposes that conversion operators that convert E to a class type with operator() defined (a function object) need also be considered in a function call expression.

In addition to making C++ more regular, this change will also considerably simplify the specification and improve the behavior of tr1::reference_wrapper.

Motivating Example: reference_wrapper

The Library Extensions Technical Report [N1660] defines, in 2.1 [tr.util.refwrap], a class template reference_wrapper<T> that is a CopyConstructible and Assignable wrapper around a reference to an object of type T.

Objects of type reference_wrapper<T> need to be usable in contexts that expect a reference to an object of type T, so reference_wrapper<T> provides a conversion operator to T&. Unfortunately, this conversion operator is typically not considered in function call expressions, even though it is desirable for reference_wrapper objects to act as function objects in such expressions. For example, two other components in the Technical Report, tr1::function and tr1::bind, are required by their specifications to be able to "call" reference_wrappers around references to function objects.

To get around this apparent limitation of the language, reference_wrapper<T> provides a family of forwarding operator() functions of the form

template<class T1, ..., class TN> typename result_of<T(T1, ..., TN)>::type operator()(T1 & a1, ..., TN & aN) const;

that return the result of calling the stored reference with the argument list a1, ..., aN. This is only an approximation due to problems with argument forwarding [N1385] and return type deduction.

The proposed change will eliminate these "approximate" operator() overloads. A reference_wrapper<T> will act as a reference to T in a function call expression.

Proposed Text

Add a new paragraph after 13.3.1.1.2/1 ([over.call.object]/1):

For each conversion function declared in T of the form

operator conversion-type-id () cv-qualifier;

where cv-qualifier is the same cv-qualification as, or a greater cv-qualification than, cv, and where conversion-type-id denotes the possibly cv-qualified class type U, or a reference to the possibly cv-qualified class type U, the function call operators of U are added to the set of candidate functions.

[Note: changes are relative to ISO/IEC 14882:2003(E).]

Impact on Existing Code

Existing code is affected in the following two situations:

The general consensus in the C++ community is that conversion operators need to be avoided whenever possible. The fact that conversions to function pointers and references are considered in a function call expression comes as a surprise even to most experts. This leads the author to believe that the first situation described above is rare, and the second (which is more dangerous because it has the potential to silently alter the meaning of code) essentially nonexistent.

--end