2149. Concerns about 20.8/5

Section: 23.14 [function.objects] Status: C++14 Submitter: Scott Meyers Opened: 2012-02-15 Last modified: 2016-02-10

Priority: Not Prioritized

View all other issues in [function.objects].

View all issues with C++14 status.

Discussion:

23.14 [function.objects] p5 says:

To enable adaptors and other components to manipulate function objects that take one or two arguments it is required that the function objects correspondingly provide typedefs argument_type and result_type for function objects that take one argument and first_argument_type, second_argument_type, and result_type for function objects that take two arguments.

I have two concerns about this paragraph. First, the wording appears to prescribe a requirement for all function objects in valid C++ programs, but it seems unlikely that that is the intent. As such, the scope of the requirement is unclear. For example, there is no mention of these typedefs in the specification for closures (5.1.2), and Daniel Krügler has explained in the thread at http://tinyurl.com/856plkn that conforming implementations can detect the difference between closures with and without these typedefs. (Neither gcc 4.6 nor VC10 appear to define typedefs such as result_type for closure types. I have not tested other compilers.)

Second, the requirement appears to be unimplementable in some cases, notably for function objects returned from std::bind, as Howard Hinnant explains in the thread at http://tinyurl.com/6q5bos4.

From what I can tell, the standard already defines which adaptability typedefs must be provided by various kinds of function objects in the specifications for those objects. Examples include the function objects specified in 23.14.5 [refwrap]- [negators]. I therefore suggest that 23.14 [function.objects]/5 simply be removed from the standard. I don't think it adds anything except opportunities for confusion.

[2012-10 Portland: Move to Open]

This wording caused confusion earlier in the week when reviewing Stefan's paper on greater<>.

This phrasing sounds normative, but is actually descriptive but uses unfortunate wording.

The main reason this wording exists is to document the protocol required to support the legacy binders in Annex D.

Stefan points out that unary_negate and binary_negate have not been deprecated and rely on this. He plans a paper to remove this dependency.

Consensus that this wording is inadequate, confusing, and probably should be removed. However, that leaves a big hole in the specification for the legacy binders, that needs filling.

While not opposed to striking this paragraph, we will need the additional wording to fix the openning hole before this issue can move forward.

[ 2013-04-14 STL provides rationale ]

Rationale:

I've concluded that Scott's original proposed resolution was correct and complete. There are two sides to this story: the producers and the consumers of these typedefs.

Producers: As Scott noted, the Standard clearly documents which function objects must provide these typedefs. Some function objects must provide them unconditionally (e.g. plus<T> (for T != void), 23.14.6 [arithmetic.operations]/1), some conditionally (e.g. reference_wrapper<T>, 23.14.5 [refwrap]/2-4), and some don't have to provide them at all (e.g. lambdas, 8.4.5 [expr.prim.lambda]). These requirements are clear, so we shouldn't change them or even add informative notes. Furthermore, because these typedefs aren't needed in the C++11 world with decltype/perfect forwarding/etc., we shouldn't add more requirements to provide them.

Consumers: This is what we were concerned about at Portland. However, the consumers also clearly document their requirements in the existing text. For example, reference_wrapper<T> is also a conditional consumer, and 23.14.5 [refwrap] explains what typedefs it's looking for. We were especially concerned about the old negators and the deprecated binders, but they're okay too. [negators] clearly says that unary_negate<Predicate> requires Predicate::argument_type to be a type, and binary_negate<Predicate> requires Predicate::first_argument_type and Predicate::second_argument_type to be types. (unary_negate/binary_negate provide result_type but they don't consume it.) 99 [depr.lib.binders] behaves the same way with Fn::first_argument_type, Fn::second_argument_type, and Fn::result_type. No additional wording is necessary.

A careful reading of 23.14 [function.objects]/5 reveals that it wasn't talking about anything beyond the mere existence of the mentioned typedefs — for example, it didn't mention that the function object's return type should be result_type, or even convertible to result_type. As the producers and consumers are certainly talking about the existence of the typedefs (in addition to clearly implying semantic requirements), we lose nothing by deleting the unnecessary paragraph.

[2013-04-18, Bristol]

Previous wording:

Remove 23.14 [function.objects] p5:

To enable adaptors and other components to manipulate function objects that take one or two arguments it is required that the function objects correspondingly provide typedefs argument_type and result_type for function objects that take one argument and first_argument_type, second_argument_type, and result_type for function objects that take two arguments.

Proposed resolution:

This wording is relative to N3485.

Edit 23.14 [function.objects] p5:

[Note:To enable adaptors and other components to manipulate function objects that take one or two arguments it is required that the function objectsmany of the function objects in this clause correspondingly provide typedefs argument_type and result_type for function objects that take one argument and first_argument_type, second_argument_type, and result_type for function objects that take two arguments.end note]