In another forum, we're dealing with functions that can usefully be made
<tgmath.h>-like generic, but for which mixing types is meaningless. I
suggested that, given the prototypes
int totalorder(double x, double y);
int totalorderf(float x, float y);
we could use the C1x keyword _Generic to define a macro totalorder(x,y)
for which
* totalorder(1.0, 2.0) => (totalorder)(1.0, 2.0)
* totalorder(1.0f, 2.0f) => (totalorderf)(1.0f, 2.0f)
* totalorder(1.0, 2.0f) => compile error
* totalorder(1.0f, 2.0) => compile error
The most obvious method of yielding a compile error in C1x is
_Static_assert, so we tried this:
#define totalorder(x,y) \
_Generic((x), \
float: _Generic((y), \
float: totalorderf, \
double: _Static_assert(0, "type mismatch")), \
double: _Generic((y), \
float: _Static_assert(0, "type mismatch")), \
double: totalorder))((x),(y))
The trouble is that _Generic expands to an expression, which
_Static_assert is not. So, to recap my question, is there some sort of
legal expression I can use that will allow the "good" generic selection
to work while producing an error -- almost any error will do -- on the
"bad" paths?
Thanks,
--Joel
sizeof(double[2*(EXP)-1]) should usually work well here.
Jens
I'll suggest another tack. Why not just remove the option of the "bad"
types in the inner _Generic expressions? A type for y that is not
compatible with the only listed option is a constraint violation so a
diagnostic is required.
--
Ben.
The original had a constant expression of 0 so one could just write
sizeof (double[-1])
but it also means that this could be used:
(0 ? totalorder : totalorderf)
(with any expression at all in place of the 0). Because the two
pointers are not to compatible types a diagnostic is required. It's
likely to be more "user friendly" than a message about the size of an
array and it might even refer to the types of one or both of the
functions (though it doesn't in gcc but it does in clang).
However, you will probably get a diagnostic even when the types
in the _Generic expressions match. The "other" expressions in a
_Generic are not evaluated, but that does not mean the compiler won't
complain about them. In fact, I think the compiler must do so unless
there is something subtle in C1x that I've missed. I.e. using an
expression that is a constraint violation in any arm of a _Generic
expression is not going to be the solution. Just leaving off that "bad"
arm will work better as I suggested elsewhere.
--
Ben.
Because .... Hmm, are you suggesting something like
#define totalorder(x,y) \
_Generic((x), \
float: _Generic((y), float: totalorderf), \
double: _Generic((y), double: totalorder)) ((x),(y))
instead? That should catch usages like
totalorder(1.0f, 2.0)
but will it catch
totalorder(1.0, 2.0f)
as well?
Is there a compiler under which I can test this?
--Joel
Exactly.
> That should catch usages like
>
> totalorder(1.0f, 2.0)
>
> but will it catch
>
> totalorder(1.0, 2.0f)
>
> as well?
I don't see why not. In the second case, 1.0 is of type double and 2.0f
id not so the inner _Generic has be a constraint violation.
> Is there a compiler under which I can test this?
The online clang documentation talked about it but my installed version
does not seem to understand them.
--
Ben.