C11 嵌套泛型

问题描述 投票:0回答:2

我正在编写一个数学库,想要进行像“add”这样的通用调用,它采用两个参数 v1 和 v2,并调用正确的函数。如果v1是vec2并且v2是vec2,那么它将调用vec2_add,如果v1是vec2并且v2是float,那么它将调用vec2_add_float。但如果 v1 是 vec3,v2 是 vec3,它将调用 vec3_add 等...底部会绘制一个小图

v1 -> vec2,v2-> vec2:调用 vec2_add v1 -> vec2, v2-> float: 调用 vec2_add_float

v1 -> vec3,v2-> vec3:调用 vec3_add v1 -> vec3,v2-> float:调用 vec3_add_float

我确实写了一个小的通用代码,如下所示:

#define add(v1, v2) _Generic((v1),                  \
                 vec2: _Generic((v2),           \
                         vec2: vec2_add,        \
                         float: vec2_add_float  \
                         ),             \
                 svec3: _Generic((v2),          \
                         vec3: vec3_add,        \
                         float: vec3_add_float  \
                         )              \
                 )(v1, v2)

出于某种原因,这适用于 add_float 类型,但当我尝试将 vec2 添加到 vec2 或将 vec3 添加到 vec3 时却不起作用,给我错误消息:

‘_Generic’ selector of type ‘vec2’ is not compatible with any association
   30 |                              vec3: _Generic((v2),                      \

我在这里做错了什么?

c generics nested c11
2个回答
0
投票

从语法上讲,

_Generic
是一个运算符,并且它的每个操作数都必须是有效的表达式,即使该操作数未被
_Generic
选择。

v1
v2
都是
vec2
时,选择外部
vec2
中的
_Generic
大小写,但
vec3
大小写(我认为
svec3
是拼写错误)必须仍然有效。这种情况下的操作数是:

_Generic((v2),
    vec3: vec3_add,
    float: vec3_add_float
)

_Generic
表达式与
v2
(a
vec2
)大小写不兼容,因此编译器会抱怨。

要解决这个问题,请为其指定默认情况。您可以使用带有空函数指针或错误处理函数的单独默认情况,例如:

_Generic((v2),
    vec3: vec3_add,
    float: vec3_add_float,
    default: (void (*)(void)) 0
)

_Generic((v2),
    vec3: vec3_add,
    float: vec3_add_float,
    default: ErrorHandlingFunction
)

或将其折叠到其他箱子之一中,例如:

_Generic((v2),
    vec3: vec3_add,
    default: vec3_add_float,
)

将来,始终针对此类问题提供“最小可重现示例”。这将使其他人不必编写额外的代码来测试可能的解决方案。


0
投票
所有

选择表达式必须是有效。当 v2

vec2
时,表达式
_Generic(v2, vec3: vec3_add, float: vec3_add_float)
无效,因为
vec3
float
都不与
vec2
兼容。
IMO,这是

通用选择

的严重设计缺陷。 解决方法是使用

default

来处理常见情况,即

vec2_add
v1
vec2
,或者
vec3_add
,如果
v1
vec3
#define add(v1, v2) _Generic((v1),              \
                 vec2: _Generic((v2),           \
                         default: vec2_add,     \
                         float: vec2_add_float  \
                         ),                     \
                 vec3: _Generic((v2),           \
                         default: vec3_add,     \
                         float: vec3_add_float  \
                         )                      \
                 )(v1, v2)

© www.soinside.com 2019 - 2024. All rights reserved.