c - 参数化的通用 C 宏
问题描述
我正在尝试在 C 中构建一个伪泛型类型。本质上,我正在尝试Option<T>
使用一个预定义的、受限制的类型列表来克隆 Rust,该列表允许为T
.
显然,C 并不真正适合这个——我这样做主要是为了看看我能走多远(而不是我期望在实际生产代码中使用的东西)。为此,任何丑陋的黑客都是公平的游戏。
到目前为止,我为所有提供的类型构建了一组单独的特定于内部类型的函数。它看起来像这样:
标题:
#pragma once
#define ALL_OPTIONS \
OPTION_INSTANCE(option_bool, bool) \
OPTION_INSTANCE(option_double, double) \
OPTION_INSTANCE(option_int, int)
#define OPTION_INSTANCE(name, inner) \
typedef struct { \
bool is_some; \
inner val; \
} name##_t;
ALL_OPTIONS
#undef OPTION_INSTANCE
#define OPTION_INSTANCE(name, inner) \
name##_t name##_some(inner val); \
name##_t name##_none(void); \
bool name##_is_some(name##_t self); \
bool name##_is_none(name##_t self); \
ALL_OPTIONS
#undef OPTION_INSTANCE
执行:
#include "option.h"
#define OPTION_INSTANCE(name, inner) \
name##_t name##_some(inner val) { \
return (name##_t) { \
.is_some = true, \
.val = val, \
}; \
} \
\
name##_t name##_none(void) { \
return (name##_t) { \
.is_some = false, \
}; \
} \
\
bool name##_is_some(name##_t self) { \
return self.is_some; \
} \
\
bool name##_is_none(name##_t self) { \
return !self.is_some; \
}
ALL_OPTIONS
#undef OPTION_INSTANCE
请注意,在我的实际代码中,我为生成的类型定义了更多函数。
这工作得很好,尽管我所做的主要是减少实现样板。下一步将是实施option_is_some
(无类型限定),它可以接受任何 option_<inner>_t
利用 C11 泛型,我可以通过手动宏来做到这一点:
#define option_is_some(self) \
_Generic((self), \
option_bool_t: option_bool_is_some, \
option_double_t: option_double_is_some, \
option_int_t: option_int_is_some, \
)(self)
但这必然会重复 中定义的类型列表ALL_OPTIONS
。我真正想做的是
#define OPTION_INSTANCE(name, inner) \
name##_t: name##_is_some,
#define option_is_some(self) \
_Generic((self), \
ALL_OPTIONS \
default: false \
)(self)
#undef OPTION_INSTANCE
但这失败了,因为在使用ALL_OPTIONS
时会扩展option_is_some
(其中OPTION_INSTANCE
将未定义)。
所以,我正在寻找替代品。我很乐意采用一种完全不同的方法来定义通用类型列表(而不是ALL_OPTIONS
hack)——但是,我确实希望保留添加新支持的内部类型只需要在单个位置进行更改的属性。
解决方案
只需访问宏本身中的成员:
#define option_is_some(self) ((self).is_some)
总的来说,你的实现很奇怪。没有一个中心ALL_OPTIONS
位置 - 一次只做一个选项,彼此分开。文件在 C 中分为头文件和源文件。
#define OPTION_HEADER(name, inner) \
typedef struct { \
bool is_some; \
inner val; \
} name##_t; \
\
name##_t name##_some(inner val); \
name##_t name##_none(void); \
bool name##_is_some(name##_t self); \
bool name##_is_none(name##_t self);
#define OPTION_SOURCE(name, inner) \
name##_t name##_some(inner val) { \
return (name##_t) { \
.is_some = true, \
.val = val, \
}; \
} \
etc...
#define OPTION_HEADER_AND_SOURCE(name, ...) \
OPTION_HEADER(name, __VA_ARGS__)
OPTION_SOURCE(name, __VA_ARGS__)
然后,您只需执行以下选项:
OPTION_HEADER_AND_SOURCE(option_bool, bool)
OPTION_HEADER_AND_SOURCE(option_double, double)
OPTION_HEADER_AND_SOURCE(option_int, int)
您可以查看我发现的其他项目:https ://github.com/tylov/STC和https://github.com/glouw/ctl,它们使用宏模板在 C 中实现各种已知容器来自 C++。
推荐阅读
- tensorflow - 在TensorFlow中将旋转变换应用于矩形的一组四个坐标
- reactjs - 从 React 应用程序外部的按钮使用 React Router 导航
- javascript - 按键值重新组合数组中对象的有效方法
- if-statement - If else 阶梯优化
- reactjs - 我无法在 react.js 中加载多个图像
- sql - 尝试在插入时创建触发器时出现多部分标识符错误
- xamarin.forms - Xamarin CollectionView - 以编程方式滚动
- angular - ngx-monaco-editor + Karma 测试运行器 - 如何将 monaco 实例加载到测试套件中?
- node.js - Mongoose,Next.JS OverwriteModelError:编译后无法覆盖模型
- abap - 迁移到 S4HANA 后,RIMARA20 程序中的 ALV 字段丢失