(C11) 泛型表达式

⭐语法

Ref: 泛型选择 (C11 起) - cppreference.com

关键词:

_Generic(控制表达式 , 关联列表)  (C11 起) 

关联列表

  • 类型名:表达式
    • 类型名:任何并非可变修改的完整对象类型(即既非 VLA 亦非指向 VLA 的指针)。
    • 表达式:任何类型和值类别的表达式(除了逗号运算符
  • default:表达式

控制表达式

  • 任何表达式(除了逗号运算符),若不使用 default 关联,则其类型必须与 类型名 之一兼容。

判定解释

控制表达式 的类型经历左值转换

只在类型域中进行转换

  • 舍弃顶层 cvr 限定符和原子属性
  • 数组到指针/函数到指针变换
  • 不实例化任何副效应或计算任何值

有类型匹配,若其类型与各关联之一的 类型名 兼容,则解释为冒号后的表达式。

无类型匹配,且提供了 default 关联,则解释为其后的表达式。

注意

关联列表 中的任意二个 类型名 不能指定兼容类型

使用关键词 default 的关联只能有一个。若不使用 default,且无一 类型名 与控制表达式类型兼容,则程序无法编译。

⭐举例

🚩判断对象类型

_Generic可以判断自定义类型。

cvr限定符对类型识别不受影响。

default不是必须写道最后一个,顺序这方面没有限制。

#include <stdbool.h>
#include <stdio.h>

struct Node {};

#define get_typename(x)             \
    _Generic((x),                   \
        default: "other",           \
        _Bool: "bool",              \
        int: "int",                 \
        char: "char",               \
        struct Node: "struct Node"  \
    )
    
int main() {
    _Bool       b = true;
    char        c = 'a';
    const int   i = 10;
    struct Node node;

    printf("Type of [_Bool] is %s\n", get_typename(b));
    printf("Type of [char] is %s\n", get_typename(c));
    printf("Type of [int] is %s\n", get_typename(i));
    printf("Type of [struct Node] is %s\n", get_typename(node));
}

🚩判断指针

对指针类型的判断仍然使用。

#include <stdio.h>

#define get_pointname(x) \
    _Generic((x),        \
        int*: "int*",    \
        void*: "void*",  \
        default: "other" \
    )

int main() {
    int   i  = 0;
    int*  ip = NULL;
    void* vp = NULL;

    printf("Type of [int] is [%s]\n", get_pointname(i));
    printf("Type of [int*] is [%s]\n", get_pointname(ip));
    printf("Type of [void*] is [%s]\n", get_pointname(vp));
}

🚩函数重载

可以根据类型指定调用的函数,注意参数个数。

下方代码展示在使用_Generic时,并且直接调用的情况。_Generic((x), default: fun)(x)

#include <math.h>
#include <stdio.h>

int default_fun() {
    printf("Line[%d], Func[%s]\n", __LINE__, __func__);
    return -1;
}

#define sqrt(x)                  \
        _Generic((x),            \
            float: sqrtf,        \
            double: sqrt,        \
            long double: sqrtl,  \
            default: default_fun \
        )(x)

int main(void) {
    int         i  = 4;
    float       f  = 4.0f;
    double      d  = 4.0;
    long double ld = 4.0L;

    printf("[i] sqrt = %d\n", sqrt(i));
    printf("[float] sqrt = %f\n", sqrt(f));
    printf("[double] sqrt = %lf\n", sqrt(d));
    printf("[long double] sqrt = %Lf\n", sqrt(ld));
}

🚩嵌套使用

由于每次_Generic只能判断一个表达式的类型,因此如果是需要用到多参的话,可以嵌套的使用_Generic

#include <stdio.h>

#define add(x, y)                              \
    _Generic((x),                              \
        int: _Generic((y),                     \
            int: (int)(x) + (int)(y),          \
            default: (int)(x) + (double)(y)    \
        ),                                     \
        default: _Generic((y),                 \
            int: (double)(x) + (int)(y),       \
            default: (double)(x) + (double)(y) \
        )                                      \
    )

int main() {
    int    i1 = 10;
    int    i2 = 20;
    double d1 = 3.14;
    double d2 = 2.71;

    printf("%d + %d = %d\n", i1, i2, add(i1, i2));  // 整数加法
    printf("%f + %f = %f\n", d1, d2, add(d1, d2));  // 浮点数加法
    printf("%d + %f = %f\n", i1, d2, add(i1, d2));  // 混合加法
}

END

关注我,学习更多C/C++,算法,计算机知识

B站:

👨‍💻主页:天赐细莲 bilibili

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值