Почему не работает называть именующее выражение

Обновить

April 2019

Просмотры

77 раз

1

Это должно быть довольно очевидно, но я не мог любой нормативно - справочный в стандарте явно , что вызов функции (не) именующий. Существует несколько связанного вопрос , но речь идет о C ++ и никаких ссылок не предусмотрена.

Просматривая 6.5.2.2(p5) Function callsтолько я смог найти

Если выражение, которое обозначает вызываемой функции имеет тип указатель на функцию, возвращающую тип объекта, выражение вызова функции имеет тот же тип, что и тип объекта, и имеет значение, определенное, как указано в 6.8.6.4

6.3.2.1(p1) говорится, что

-Значение является выражением (с типом объекта другой thanvoid), что potentiallydesignates объект

Так что я пытался найти, если вызов функции обозначает объект. Не указано в стандарте, если результат вызова функции имеет срок хранения и срок службы. Так как любой объект имеет срок хранения и срок службу я пришел к выводу, что любое выражение вызова функции не обозначает объект, следовательно, не в именующем выражение.

Но это кажется запутанным и сложным. В частности , я нашел пример 6.5.2.3(p7):

Пример 1. Если F является функция возвращает структуру или объединение, и х является членом этой структуры или объединений, f().x isдействительного выражение постфикса , но не именующий.

Судя по этому примеру , если f()бы именующий f().xтакже будет именующей. Но примеры являются информативными , которые заставили меня запутался.

2 ответы

2

The return value of a function is not an lvalue as the Standard defines the term, but there are contexts where it would offer the semantics of one.

Given any structure type:

struct foo {...whatever... };

one can write a function whose return value can be used in ways that would require an lvalue of type struct foo [most typically passing the address of such an lvalue to another function].

struct wrapped_foo {struct foo it[1];} wrap_foo(foo it)
{
  struct wrapped_foo ret = {it};
  return ret;
}
extern void do_something(int,int,int,struct foo const *p,int,int,int);
void demo_of_passing_address_of_a_foo(struct foo x)
{
  do_something(1,2,3,&(wrap_foo(x).it[0]),4,5,6);
}

Note that while the return value of wrap_foo(x) isn't an lvalue, wrap_foo(x).it[0] is one, and its address can be taken. The lifetime of the object identified thereby will extend through the evaluation of the enclosing expression, i.e. the call to do_something. If the subscripting operator were defined in its own right as an operator which does not result in array-to-pointer decomposition but simply yields a value of the element type, which would be an lvalue only when the array was one, then wrap_foo(x).it[0] would not be an lvalue, and issues of lifetime would be irrelevant.

While the ability to pass the address of a temporary is useful, it adds compiler complexity by requiring that a compiler given something like the above allocate space for wrap_foo's return value before stacking any of the arguments to the outer function call. If such compiler complexity is required, it could just as well allow such semantics to be achieved by allowing top-level argument expressions to use & on values of arbitrary type (yielding a const-qualified pointer to an object whose lifetime would be that of the outer enclosing expression).

1

It's not an lvalue because its described as a "value" in the paragraph you quoted. The standard explicitly mentions when an expression has the property of being an lvalue. For instance:

6.5.3.2 Address and indirection operators (emphasis mine)

4 The unary * operator denotes indirection. If the operand points to a function, the result is a function designator; if it points to an object, the result is an lvalue designating the object. If the operand has type ''pointer to type'', the result has type ''type''. If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.

As for accessing a union or member. The standard doesn't require the postfix expression in expr.id to be an lvalue. On the contrary. The whole member access has the same value category as the postfix expression:

6.5.2.3 Structure and union members (emphasis mine)

3 A postfix expression followed by the . operator and an identifier designates a member of a structure or union object. The value is that of the named member, and is an lvalue if the first expression is an lvalue. If the first expression has qualified type, the result has the so-qualified version of the type of the designated member.

So in the example you quoted, f().x is a value, and not an lvalue, because f() itself is not an lvalue.