Feature Request: unary + for rvalue conversion of arbitrary types

Problem statement

To use generic selection primary expressions comfortably it would be convenient to have a possibility to perform some sort of lvalue to rvalue conversion to the controlling expression:

#define cbrt(X)        \
_Generic(+(X),         \
  long double: cbrtl,  \
  default: cbrt,       \
  float: cbrtf         \
)(X)

Under the assumption that types of rvalues are always unqualified, here the prefix operator + in the selection expression ensures that lvalue conversion on arithmetic types is performed such that e.g lvalues of type float const select cbrtf and not the default cbrt. Otherwise, for the same effect, the generic association list would have to list all 8 qualified version of long double and float, respectively.

For programming with type generic expressions it would be convenient to have a generic tool that allows to drop qualifiers in same spirit as for cbrt above:

#define LOCK(X)           \
_Generic(UNQUALIFY(*(X)), \
  mtx_t: mtx_lock,        \
  sem_t: sem_wait,        \
)(X)

In the current version of the standard there is no generic tool that would transform an lvalue of any type into an rvalue expression of the same type or that would allow to drop all qualifiers from the type. There are only partial solutions:

The later form can be used to cook a generic expression that results in an appropriate rvalue for all scalar types.

#define UNQUALIFY_SCALAR(X) _Generic((X),              \
  default: (X)+0,                                      \
  _Bool: (_Bool)(X),                                   \
  _Bool const: (_Bool)(X),                             \
  _Bool volatile: (_Bool)(X),                          \
  _Bool const volatile: (_Bool)(X),                    \
  _Bool _Atomic: (_Bool)(X),                           \
  _Bool _Atomic const: (_Bool)(X),                     \
  _Bool _Atomic volatile: (_Bool)(X),                  \
  _Bool _Atomic const volatile: (_Bool)(X),            \
   ... same expansion for the other narrow types ...   \
)

This expression has to cover all possible combinations of qualifiers for all the 6 narrow integer types, that is in total 48 special cases.

For our example of LOCK currently no generic implementation of an UNQUALIFY macro is known. So instead to implement LOCK 16 different cases would be needed in the selection list. Coding such type generic expression systematically in production code is difficult to maintain and such enumerative solutions observably increase compilation times.

Proposed modification

Replace the beginning of 6.5.3.3 by the following

6.5.3.3 Unary arithmetic operators
Constraints
The operand of the unary - operator shall have arithmetic type; of the ~ operator, integer type; of the ! operator, scalar type.

Add a new section for the unary + operator:

6.5.3.X The unary + operator
Semantics
If the operand of the unary + operator is not of an array type, the result shall be the value of its operand with a result type that is the unqualified type of its operand. If it is of array type, the operand shall first undergo an array to pointer conversion (6.3.2.1p3).

C all previous standards: For expression that use the unary + operator outside type generic expression this modification slightly changes the order in which type promotion is effected in the abstract machine. Whereas before that modification a promotion (e.g of short to int) would have occurred prior to an application of the operator, with this modification the promotion would only be performed on the result of the + operator once it is itself the operand of another operator. This difference is not be observable by any program, unless it uses a _Generic primary expression.

C11: When used in _Generic primary expressions the difference would become observable by a program. But expressions that knowingly use a + operator, e.g to force a type promotion, should be marginal.


Author: Jens Gustedt, INRIA, 2012