组合通用宏 我对C11的一般机制感到高兴——切换类型是我从C++中错过的东西。然而,事实证明它很难作曲

组合通用宏 我对C11的一般机制感到高兴——切换类型是我从C++中错过的东西。然而,事实证明它很难作曲,c,c11,C,C11,例如,给定函数: bool write_int(int); bool write_foo(foo); bool write_bar(bar); // bool write_unknown is not implemented 然后我就可以写了 #define write(X) _Generic((X), \ int : write_int, \ foo: write_foo, \ bar: write_bar, \ default: write_unknown)(X) 而且,

例如,给定函数:

bool write_int(int);
bool write_foo(foo);
bool write_bar(bar);
// bool write_unknown is not implemented
然后我就可以写了

#define write(X) _Generic((X), \
  int : write_int, \
  foo: write_foo, \
  bar: write_bar, \
  default: write_unknown)(X)
而且,如果我不尝试使用&write或将其传递给函数,我可以调用write(obj),如果obj是其中一种类型的实例,那么一切都很好

然而,一般来说,foo和bar是完全无关的。它们在不同的头文件中定义,很少(但偶尔)在单个源文件中一起使用。那么扩展到_Generic的宏应该写在哪里呢

目前,我正在积累名为write.h、equal.h、copy.h、move.h的头文件,每个头文件都包含一组函数原型和一个_泛型。这是可行的,但并不明智。我不喜欢在一个地方收集程序中每种类型的列表

我希望能够在头文件中定义foo类型,以及函数write\u foo,并以某种方式使客户机代码能够调用“函数”write。默认值看起来像一个向量,通过它可以实现这一点

我能在这个网站上找到的最接近的匹配项是有部分解决方案的,但这还不足以让我了解如何组合各种宏

假设,在定义write_bar的头文件中,我们有一个现有的宏定义:

#define write(x) _Generic((x), bar: write_bar, default: some_magic_here)(x)
或者我们可以省略尾随(x)

在这个标题下面,我想要一个write()版本,它可以处理foo或bar。我认为它需要在默认情况下调用现有的宏,但我认为预处理器无法重命名现有的write宏。如果它能够做到这一点,以下几点可能会起作用:

#ifndef WRITE_3
#define WRITE_3(X) write(x)
#undef write(x)
#define write(x) __Generic((x),foo: write_foo,default: WRITE_3)(x)
刚刚打出来,我可以看到一条前进的道路:

// In bar.h
#ifndef WRITE_1
#define WRITE_1(x) __Generic((x), bar: write_bar)
#elif !defined(WRITE_2)
#define WRITE_2(x) __Generic((x), bar: write_bar)
#elif !defined(WRITE_3)
#define WRITE_3(x) __Generic((x), bar: write_bar)
#endif
// In foo.h
#ifndef WRITE_1
#define WRITE_1(x) __Generic((x), foo: write_foo)
#elif !defined(WRITE_2)
#define WRITE_2(x) __Generic((x), foo: write_foo)
#elif !defined(WRITE_3)
#define WRITE_3(x) __Generic((x), foo: write_foo)
#endif
// In write.h, which unfortunately needs to be included after the other two
// but happily they can be included in either order
#ifdef WRITE_2
#define write(x) WRITE_1(x) WRITE_2(x) (x)
#elif
// etc
#endif
但是,这实际上不起作用,因为当x与参数列表不匹配时,我找不到使WRITE_N(x)扩展为空的方法。我看到了错误

controlling expression type 'struct foo' not compatible with any generic association type

我认为,要在多个文件|宏之间分发write()定义,我需要解决上述任一问题。在默认情况下,一个_泛型子句可以减少为零,如果所有类型都不匹配,它也可以减少为零

如果函数采用指向结构的指针而不是结构的实例,并且我提供write_void(void*x){(void)x;}作为默认选项,那么代码将编译并运行。但是,扩展write as

write(x) => write_void(x); write_foo(x); write_void(x);
很明显,它本身就很糟糕,而且我真的不想通过指针传递所有东西


那么,有人能找到一种方法来逐步定义一个单一的_泛型“函数”,即不从它将映射的所有类型的列表开始吗?谢谢。

大致根据鲁申科对我的回答,我想出了以下可怕的解决方案。它要求参数通过指针传递,而涉及的样板文件非常糟糕。但它确实编译并运行,其方式允许函数返回一个值

// foo.h
#ifndef FOO
#define FOO
#include <stdio.h>
#include <stdbool.h>

struct foo
{
  int a;
};

static inline int write_foo(struct foo* f)
{
  (void)f;
  return printf("Writing foo\n");
}

#if !defined(WRITE_1)
#define WRITE_1
#define WRITE_PRED_1(x) _Generic((x), struct foo * : true, default : false)
#define WRITE_CALL_1(x)                         \
  _Generic((x), struct foo *                    \
           : write_foo((struct foo*)x), default \
           : write_foo((struct foo*)0))

#elif !defined(WRITE_2)
#define WRITE_2
#define WRITE_PRED_2(x) _Generic((x), struct foo * : true, default : false)
#define WRITE_CALL_2(x)                         \
  _Generic((x), struct foo *                    \
           : write_foo((struct foo*)x), default \
           : write_foo((struct foo*)0))
#elif !defined(WRITE_3)
#define WRITE_3
#define WRITE_PRED_3(x) _Generic((x), struct foo * : true, default : false)
#define WRITE_CALL_3(x)                         \
  _Generic((x), struct foo *                    \
           : write_foo((struct foo*)x), default \
           : write_foo((struct foo*)0))
#endif

#endif

// bar.h
#ifndef BAR
#define BAR
#include <stdio.h>
#include <stdbool.h>

struct bar
{
  int a;
};

static inline int write_bar(struct bar* b)
{
  (void)b;
  return printf("Writing bar\n");
}

#if !defined(WRITE_1)
#define WRITE_1
#define WRITE_PRED_1(x) _Generic((x), struct bar * : true, default : false)
#define WRITE_CALL_1(x)                         \
  _Generic((x), struct bar *                    \
           : write_bar((struct bar*)x), default \
           : write_bar((struct bar*)0))

#elif !defined(WRITE_2)
#define WRITE_2
#define WRITE_PRED_2(x) _Generic((x), struct bar * : true, default : false)
#define WRITE_CALL_2(x)                         \
  _Generic((x), struct bar *                    \
           : write_bar((struct bar*)x), default \
           : write_bar((struct bar*)0))
#elif !defined(WRITE_3)
#define WRITE_3
#define WRITE_PRED_3(x) _Generic((x), struct bar * : true, default : false)
#define WRITE_CALL_3(x)                         \
  _Generic((x), struct bar *                    \
           : write_bar((struct bar*)x), default \
           : write_bar((struct bar*)0))
#endif

#endif

// write.h
#ifndef WRITE
#define WRITE

#if defined(WRITE_3)
#define write(x)                                                        \
  WRITE_PRED_1(x) ? WRITE_CALL_1(x) : WRITE_PRED_2(x) ? WRITE_CALL_2(x) \
                                                      : WRITE_CALL_3(x)
#elif defined(WRITE_2)
#define write(x) WRITE_PRED_1(x) ? WRITE_CALL_1(x) : WRITE_CALL_2(x)

#elif defined(WRITE_1)
#define write(x) WRITE_CALL_1(x)
#else
#error "Write not defined"
#endif

#endif

// main.c
#include "foo.h"
#include "bar.h"

#include "write.h"

int main()
{
  struct foo f;
  struct bar b;

  int fi = write(&f);
  int bi = write(&b);

  return fi + bi;
}
//foo.h
#伊夫德福酒店
#定义FOO
#包括
#包括
结构foo
{
INTA;
};
静态内联int write_foo(结构foo*f)
{
(f)无效;
返回printf(“写入foo\n”);
}
#如果!已定义(写入1)
#定义WRITE_1
#定义WRITE_PRED_1(x)_Generic((x),struct foo*:true,default:false)
#定义写入调用1(x)\
_通用((x),结构foo*\
:write_foo((struct foo*)x),默认值\
:write_foo((结构foo*)0))
#艾利夫!已定义(写入2)
#定义WRITE_2
#定义WRITE_PRED_2(x)_Generic((x),struct foo*:true,default:false)
#定义写入调用2(x)\
_通用((x),结构foo*\
:write_foo((struct foo*)x),默认值\
:write_foo((结构foo*)0))
#艾利夫!已定义(写入3)
#定义WRITE_3
#定义WRITE_PRED_3(x)_Generic((x),struct foo*:true,default:false)
#定义写入调用3(x)\
_通用((x),结构foo*\
:write_foo((struct foo*)x),默认值\
:write_foo((结构foo*)0))
#恩迪夫
#恩迪夫
//酒吧
#ifndef棒
#定义栏
#包括
#包括
结构条
{
INTA;
};
静态内联int写_栏(结构栏*b)
{
(b)无效;
返回printf(“书写条”);
}
#如果!已定义(写入1)
#定义WRITE_1
#定义WRITE_PRED_1(x)_Generic((x),结构条*:true,默认值:false)
#定义写入调用1(x)\
_通用((x),结构条*\
:write_bar((结构栏*)x),默认值\
:写入工具栏((结构栏*)0))
#艾利夫!已定义(写入2)
#定义WRITE_2
#定义WRITE_PRED_2(x)_Generic((x),结构条*:true,默认值:false)
#定义写入调用2(x)\
_通用((x),结构条*\
:write_bar((结构栏*)x),默认值\
:写入工具栏((结构栏*)0))
#艾利夫!已定义(写入3)
#定义WRITE_3
#定义WRITE_PRED_3(x)_Generic((x),结构条*:true,默认值:false)
#定义写入调用3(x)\
_通用((x),结构条*\
:write_bar((结构栏*)x),默认值\
:写入工具栏((结构栏*)0))
#恩迪夫
#恩迪夫
//写
#ifndef写入
#定义写入
#如果已定义(写入3)
#定义写入(x)\
写下1(x)?写呼叫1(x):写预定2(x)?写呼叫2(x)\
:WRITE_CALL_3(x)
#定义的elif(写入2)
#定义写入(x)写入前1(x)?写呼叫1(x):写呼叫2(x)
#定义的elif(写入1)
#定义写入(x)写入调用(x)
#否则
#错误“写入未定义”
#恩迪夫
#恩迪夫
//main.c
#包括“foo.h”
#包括“bar.h”
#包括“write.h”
int main()
{
结构foo f;
结构条b;
int-fi=写入(&f);
int bi=写入(&b);
返回fi+bi;
}
我真的希望有一个更好的w
write(x) => write_void(x); write_foo(x); write_void(x);
// foo.h
#ifndef FOO
#define FOO
#include <stdio.h>
#include <stdbool.h>

struct foo
{
  int a;
};

static inline int write_foo(struct foo* f)
{
  (void)f;
  return printf("Writing foo\n");
}

#if !defined(WRITE_1)
#define WRITE_1
#define WRITE_PRED_1(x) _Generic((x), struct foo * : true, default : false)
#define WRITE_CALL_1(x)                         \
  _Generic((x), struct foo *                    \
           : write_foo((struct foo*)x), default \
           : write_foo((struct foo*)0))

#elif !defined(WRITE_2)
#define WRITE_2
#define WRITE_PRED_2(x) _Generic((x), struct foo * : true, default : false)
#define WRITE_CALL_2(x)                         \
  _Generic((x), struct foo *                    \
           : write_foo((struct foo*)x), default \
           : write_foo((struct foo*)0))
#elif !defined(WRITE_3)
#define WRITE_3
#define WRITE_PRED_3(x) _Generic((x), struct foo * : true, default : false)
#define WRITE_CALL_3(x)                         \
  _Generic((x), struct foo *                    \
           : write_foo((struct foo*)x), default \
           : write_foo((struct foo*)0))
#endif

#endif

// bar.h
#ifndef BAR
#define BAR
#include <stdio.h>
#include <stdbool.h>

struct bar
{
  int a;
};

static inline int write_bar(struct bar* b)
{
  (void)b;
  return printf("Writing bar\n");
}

#if !defined(WRITE_1)
#define WRITE_1
#define WRITE_PRED_1(x) _Generic((x), struct bar * : true, default : false)
#define WRITE_CALL_1(x)                         \
  _Generic((x), struct bar *                    \
           : write_bar((struct bar*)x), default \
           : write_bar((struct bar*)0))

#elif !defined(WRITE_2)
#define WRITE_2
#define WRITE_PRED_2(x) _Generic((x), struct bar * : true, default : false)
#define WRITE_CALL_2(x)                         \
  _Generic((x), struct bar *                    \
           : write_bar((struct bar*)x), default \
           : write_bar((struct bar*)0))
#elif !defined(WRITE_3)
#define WRITE_3
#define WRITE_PRED_3(x) _Generic((x), struct bar * : true, default : false)
#define WRITE_CALL_3(x)                         \
  _Generic((x), struct bar *                    \
           : write_bar((struct bar*)x), default \
           : write_bar((struct bar*)0))
#endif

#endif

// write.h
#ifndef WRITE
#define WRITE

#if defined(WRITE_3)
#define write(x)                                                        \
  WRITE_PRED_1(x) ? WRITE_CALL_1(x) : WRITE_PRED_2(x) ? WRITE_CALL_2(x) \
                                                      : WRITE_CALL_3(x)
#elif defined(WRITE_2)
#define write(x) WRITE_PRED_1(x) ? WRITE_CALL_1(x) : WRITE_CALL_2(x)

#elif defined(WRITE_1)
#define write(x) WRITE_CALL_1(x)
#else
#error "Write not defined"
#endif

#endif

// main.c
#include "foo.h"
#include "bar.h"

#include "write.h"

int main()
{
  struct foo f;
  struct bar b;

  int fi = write(&f);
  int bi = write(&b);

  return fi + bi;
}
int compare (const void* p1, const void* p2)
#define compare(type, x, y) (compare_ ## type(x, y))
// int.c
int compare_int (const void* p1, const void* p2)
{
  return *(int*)p1 - *(int*)p2;
}
if( compare(int, a, b) == 0 )
{
  // equal
}
// interface.h
typedef int compare_t (const void* p1, const void* p2);

typedef struct data_t data_t; // incomplete type

typedef struct
{
  compare_t* compare;
  data_t*    data;
} interface_t;
//xy.c
struct data_t
{
  int x;
  int y;
};

static int compare_xy (const void* p1, const void* p2)
{
  // compare an xy object in some meaningful way
}

void xy_create (interface_t* inter, int x, int y)
{
  inter->data = malloc(sizeof(data_t));
  assert(inter->data != NULL);

  inter->compare = compare_xy;
  inter->data->x = x;
  inter->data->y = y;
}