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
.
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_wrapper
s
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.
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 typeU
, the function call operators ofU
are added to the set of candidate functions.
[Note: changes are relative to ISO/IEC 14882:2003(E).]
Existing code is affected in the following two situations:
T
contains both function call operators and a conversion to a
function object type U
and one of the function call operators in
U
is a better match than all of the function call operators in T
.
The call is ambiguous because the implicit object parameter needs a
user-defined conversion to match U
;
T
contains a conversion to a pointer or a reference to a function
and a conversion to a function object type U
.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