Take the following example code:
void test(const Item& item = Item()) {
...
}
Assume that, once item has been passed to the function, this cannot throw.
The question is: the function should be marked noexcept or noexcept(noexcept(Item()))?
IHMO, the former should be ok, but I am not sure. A quotation from the standard would be very appreciated!
Default arguments are shortcut notations for the caller of function. So, when the function executes, the construction is already complete.
Thus, noexcept should be sufficient.
In the standard [dcl.fct.default] states:
If an initializer-clause is specified in a parameter-declaration this
initializer-clause is used as a default argument. Default arguments will be used in calls where trailing arguments are missing.
Example:
the declaration
void point(int = 3, int = 4);
declares a function that can be called with zero, one, or two arguments of type int. It can be called in
any of these ways:
point(1,2); point(1); point();
The last two calls are equivalent to
point(1,4) and point(3,4) , respectively.
Also there is a note (in [intro.execution] Program execution):
Subexpressions involved in evaluating default arguments (8.3.6) are
considered to be created in the expression that calls the function, not the expression that defines the default
argument
Related
I read that this code A a( A() ); was interpreted by the compiler as a function declaration while here I clearly see that A() is a function that returns an object. How can it be something else that the construction of a A object ?
I've just read entirely the Function declaration page of cppreference : https://en.cppreference.com/w/cpp/language/function and I don't see anywhere that the parameters list can look like that A().
I don't understand how The most vexing parse can be valid C++.
A() isn't a function declaration by itself, but it can be the type of a function.
For instance, suppose I declare the following function: A makeAnA();. The type of makeAnA is A(): A function that takes no arguments and returns an A.
Quoting cppreference on functions:
Each function has a type, which consists of the function's return type, the types of all parameters (after array-to-pointer and function-to-pointer transformations, see parameter list) , whether the function is noexcept or not (since C++17), and, for non-static member functions, cv-qualification and ref-qualification (since C++11). Function types also have language linkage.
So a function that has zero parameters, returns an A, and isn't noexcept has the type A().
Therefore, it's possible to interpret A a( A() ); as a function declaration. It declares that a accepts a single, unnamed argument of type A(), and returns an A as its result. Because it's possible to interpret this as a function declaration, it is required by the standard that it is so interpreted.
This question already has an answer here:
Using a parameter's name inside its own default value - is it legal?
(1 answer)
Closed last year.
If one defines a new variable in C++, then the name of the variable can be used in the initialization expression, for example:
int x = sizeof(x);
And what about default value of a function argument? Is it allowed there to reference the argument by its name? For example:
void f(int y = sizeof(y)) {}
This function is accepted in Clang, but rejected in GCC with the error:
'y' was not declared in this scope
Demo: https://gcc.godbolt.org/z/YsvYnhjTb
Which compiler is right here?
According to the C++17 standard (11.3.6 Default arguments)
9 A default argument is evaluated each time the function is called
with no argument for the corresponding parameter. A parameter shall
not appear as a potentially-evaluated expression in a default
argument. Parameters of a function declared before a default
argument are in scope and can hide namespace and class member name
It provides the following example:
int h(int a, int b = sizeof(a)); // OK, unevaluated operand
So, this function declaration
void f(int y = sizeof(y)) {}
is correct because, in this expression sizeof(y), y is not an evaluated operand, based on C++17 8.3.3 Sizeof:
1 The sizeof operator yields the number of bytes in the object
representation of its operand. The operand is either an expression,
which is an unevaluated operand (Clause 8), or a parenthesized
type-id.
and C++17 6.3.2 Point of declaration:
1 The point of declaration for a name is immediately after its
complete declarator (Clause 11) and before its initializer (if any),
except as noted below.
The code does not appear ill-formed, so Clang is alright.
[basic.scope.pdecl]
1 The point of declaration for a name is immediately after its complete declarator ([dcl.decl]) and before its initializer (if any), except as noted below.
This is the notorious passage that is under discussion. I bring it here just to mention that "except as noted below" doesn't include any mention of default arguments. So y is declared right before = sizeof(y).
The other relevant paragraph is
[dcl.fct.default]
9 A default argument is evaluated each time the function is called with no argument for the corresponding parameter. A parameter shall not appear as a potentially-evaluated expression in a default argument. Parameters of a function declared before a default argument are in scope and can hide namespace and class member names.
sizeof(y) is not potentially evaluated, so this is also fine.
Seeing as the first paragraph makes y available as a name, and it's used in a way that is not illegal, must be some quirk of GCC that rejects the code.
Though personally, I don't see it as a great loss. This is not the most practical bit of code.
In the following code, is the return value correctly created. I have some doubt as both the arguments to the pair constructor are related. Does the use of move for second argument corrupts the first argument. Or if the first argument is always created before the second argument:
class A
{
private:
struct B
{
int a;
string b;
int c;
};
struct C
{
double d;
float f;
};
struct Key
{
int a;
string b;
double d;
};
struct Data
{
B x;
C y;
};
public:
Data data;
using ReturnType = pair<Key, Data>;
ReturnType operator()(Source input)
{
// use input to fill Data
return {{data.x.a, data.x.b, data.y.d}, move(this->data)};
}
};
Note: Source may be database cursor, standard input stream, or may be a file pointer containing relevant data.
Does c++ standard define the order in which the pair will be created. Is there any difference between c++11 and c++17 regarding this.
From this evaluation order reference:
In list-initialization, every value computation and side effect of a given initializer clause is sequenced before every value computation and side effect associated with any initializer clause that follows it in the brace-enclosed comma-separated list of initalizers.
What it is saying is that in the expression
{{data.x.a, data.x.b, data.y.d}, move(this->data)}
the {data.x.a, data.x.b, data.y.d} part will be sequenced before (i.e. evaluated before) move(this->data).
n3337, The C++11 standard draft, contains this passage
[dcl.init.list]
4 Within the initializer-list of a braced-init-list, the
initializer-clauses, including any that result from pack expansions
([temp.variadic]), are evaluated in the order in which they appear.
That is, every value computation and side effect associated with a
given initializer-clause is sequenced before every value computation
and side effect associated with any initializer-clause that follows it
in the comma-separated list of the initializer-list. [ Note: This
evaluation ordering holds regardless of the semantics of the
initialization; for example, it applies when the elements of the
initializer-list are interpreted as arguments of a constructor call,
even though ordinarily there are no sequencing constraints on the
arguments of a call. — end note ]
So when using brace initialization, the argument to initialize the Key in the ReturnType is going to be evaluated in full before the argument for the Data.
There is similar wording in every C++ standard since.
According to this, a function declared with constexpr must satisfy a few requirements, one of which is as follows:
there exists at least one argument value such that an invocation of the function could be an evaluated subexpression of a core constant expression ...
Well, constexpr function can have no arguments:
constexpr int Bar( /* empty */ ) { return 0xFF; }
constexpr int value = Bar(); // Valid expression
constexpr function that is invoked as a sub-routine can not determine the whole expression to be core constant expression either.
So what does it mean by one argument value must exist?
[Update for future readers]
Apparently the description about the requirements of constexpr function has been fixed since this question from:
there exists at least one argument value such that an invocation of the function could be an evaluated subexpression of a core constant expression ...
to:
there exists at least one set of argument values such that an invocation of the function could be an evaluated subexpression of a core constant expression ...
The quote from en.cppreference.com is not accurate in regards to the standard, the real quote is (§7.1.5/5):
For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression (5.20) [...] the program is ill-formed; no diagnostic required.
Which basically says that there must exist one valid set of arguments (the empty set being a valid one in your case).
"One argument value" here means "one set of arguments". Nullary functions have one possible argument set, the empty set.
In your case, this single empty argument set does lead to a valid constexpr call, so everything is fine.
Let we have procedure formed as class. Only constructor call makes some side effect. No need to handle class instance in memory after call. Following code instantiate that class:
struct A{
A(int){}
};
int main() {
A(0);//right. Pass const to ctor
int x=0;
A(x);//bad. Compiler interpret like A x;
(A(x));//right. New temporary object passed to brackets
A((int)x);//right. Pass temporary int to ctor
return 0;
}
(see also on Online IDE)
Why A(x); interpret as variable x declaration instead of temporary A object instantiaton?
From the C++11 standard, ISO/EIC 14882 §6.8 [stmt.ambig] ¶1 (emphasis mine):
There is an ambiguity in the grammar involving expression-statements and declarations: An expression-statement with a function-style explicit type conversion (5.2.3) as its leftmost subexpression can be indistinguishable
from a declaration where the first declarator starts with a (. In those cases the statement is a declaration.
To apply this to your question, A(x); can parse as either "call the function A / construct a temporary object of type A, and pass x as the only function/constructor argument" or "declare a variable x of type A." The standard says that in this case, it should be parsed as a variable declaration.
Your other examples are not ambiguous because they cannot be parsed as a variable declaration, and so they are parsed as a call to A's constructor.
That's because what you consider should be the parameter list to the ctor, (x) is being interpreted as "x in parentheses". Thus, A(x) is read as A (x) is read as A x.
In the other cases, the compiler has a hint suggesting that it should generate an A instance, calling the ctor with the arguments supplied.