Title
Argument-dependent lookup of lambdas used in default arguments
Status
c++14
Section
7.5.6 [expr.prim.lambda]
Submitter
Michael Wong

Created on 2013-04-15.00:00:00 last changed 122 months ago

Messages

Date: 2014-02-15.00:00:00

[Moved to DR at the February, 2014 meeting.]

Date: 2013-09-15.00:00:00

Proposed resolution (September, 2013):

Change 13.9.2 [temp.inst] paragraph 13 as follows:

If a function template f is called in a way that requires a default argument to be used, the dependent names are looked up, the semantics constraints are checked, and the instantiation of any template used in the default argument is done as if the default argument had been an initializer used in a function template specialization with the same scope, the same template parameters and the same access as that of the function template f used at that point, except that the scope in which a closure type is declared (7.5.6 [expr.prim.lambda]) — and therefore its associated namespaces — remain as determined from the context of the definition for the default argument. This analysis is called default argument instantiation. The instantiated default argument is then used as the argument of f.
Date: 2013-10-14.00:00:00
N3690 comment CA 18

According to 7.5.6 [expr.prim.lambda] paragraph 3,

The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding lambda-expression. [Note: This determines the set of namespaces and classes associated with the closure type (6.5.4 [basic.lookup.argdep]). The parameter types of a lambda-declarator do not affect these associated namespaces and classes. —end note]

However, 13.9.2 [temp.inst] paragraph 13 says,

If a function template f is called in a way that requires a default argument to be used, the dependent names are looked up, the semantics constraints are checked, and the instantiation of any template used in the default argument is done as if the default argument had been an initializer used in a function template specialization with the same scope, the same template parameters and the same access as that of the function template f used at that point.

A possibility, then, is that the closure type for a lambda expression in a default argument for a template function (or, presumably, a member function of a class template) is to be considered as having been declared in some block scope in the body of the fictional function template specialization.

Consider the following example:

  namespace J {
    inline namespace K {
      template <typename T> int zap(const T &t) { foo(t); return 0; }
      template <typename T> void zip(int = zap([] { })) { }
    }
    template <typename T> void foo(const T &) { }
  }
  void bar() { J::K::zip<long>(); }

If zip were not a template, argument-dependent lookup successfully resolves the lookup for foo in all implementations tested; however, there is implementation variance in the handling of the example as written.

(See also issue 1690.)

History
Date User Action Args
2014-11-24 00:00:00adminsetstatus: dr -> c++14
2014-03-03 00:00:00adminsetmessages: + msg4940
2014-03-03 00:00:00adminsetstatus: ready -> dr
2013-10-14 00:00:00adminsetmessages: + msg4576
2013-10-14 00:00:00adminsetstatus: open -> ready
2013-04-15 00:00:00admincreate