参数化的通用C宏

时间:2018-09-07 01:11:01

标签: c generics c-preprocessor

我正在尝试在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_OPTIONSoption_is_some被扩展了(其中OPTION_INSTANCE是不确定的)。

因此,我正在寻找替代方案。我很乐意使用一种根本不同的方法来定义类型的通用列表(而不是ALL_OPTIONS hack);但是,我确实想保留以下属性:添加新的受支持内部类型仅需要更改在一个位置。

0 个答案:

没有答案