如果一个羊羔被宣布为默认参数,每个呼叫站点是否不同?
原标题:If a lambda is declared as a default argument, is it different for each call site?
#include
int foo(int x = [](){ static int x = 0; return ++x; }()) { return x; };
int main() {
std::cout << foo() << foo(); // prints "12", not "11"
}
I know that default arguments are evaluated each time a function is called. Does that mean that the lambda type is different on each call? If not, please point to the standard quote explaining why it is so.
问题回答
This example from dcl.fct.default makes pretty clear that the intent is that the point where the default argument is defined also defines the semantics:
int a = 1;
int f(int);
int g(int x = f(a)); // default argument: f(::a)
void h() {
a = 2;
{
int a = 3;
g(); // g(f(::a))
}
}
In particular, the default argument is not just a token sequence that is inserted at the point of the function call and then analysed.
Following this intent, the lambda expression is analysed at the point of definition of the default argument, not at the point of function call. Therefore, there is only one lambda type, not many, and the correct result is 12.
The Standard doesn t express this clearly enough with regards to lambda expressions being used as default arguments, though.
Does that mean that the lambda type is different on each call?
No, because evaluation happens at runtime(during execution) but the type are fixed at compile time in c++. Basically, creating new types with function calls isn t allowed in c++(it being a statically typed language).
This can be seen from static type s documentation:
static type
type of an expression resulting from analysis of the program without considering execution semantics
[Note 1: The static type of an expression depends only on the form of the program in which the expression appears, and does not change while the program is executing. — end note]
Thus the output 12 produced by different compilers is correct.
You are right that each lambda expression is associated with a unique closure type, however it is the expression itself, not how many times it is evaluated, which determines the type.
Because we are talking about a lambda expression, we are dealing with a prvalue. Evaluating a prvalue initialises an object, which has exactly one type. [expr.prim.lambda.closure] [dcl.fnc.default] [basic.lval] [intro.object]
A lambda-expression is a prvalue whose result object is called the closure object.
The type of a lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type, called the closure type, whose properties are described below.
A default argument is evaluated each time the function is called with no argument for the corresponding parameter.
A prvalue is an expression whose evaluation initializes an object or computes the value of an operand of an operator, as specified by the context in which it appears, or an expression that has type cv void.
The properties of an object are determined when the object is created. An object can have a name. An object has a storage duration which influences its lifetime. An object has a type.
An expression remains the same type throughout execution [defns.static.type]
static type
type of an expression resulting from analysis of the program without considering execution semantics
12 is the correct result for your example.
相关问题
热门标签
- winforms
- combobox
- fogbugz
- java
- date
- internationalization
- asp.net
- iis
- url-rewriting
- urlrewriter
- c#
- enums
- ocaml
- haxe
- algorithm
- string
- viewstate
- .net
- c++
- c
- symbol-table
- mysql
- database
- postgresql
- licensing
- migration
- vb.net
- vb6
- declaration
- vb6-migration
- python
- psycopg2
- backup
- vmware
- virtualization
- gnu-screen
- authentication
- desktop
- excel
- xll
- cultureinfo
- regioninfo
- oracle
- client
- session
- download
- html
- virtual
- constructor
- scenarios
- perl
- full-text-search
- javascript
- ajax
- testing
- oop
- inheritance
- vim
- encapsulation
- information-hiding