C11:对类型本身(不是类型的实例)使用“_Generic()”(或其他东西)?

C11: Using `_Generic()` (or something) for types themselves (not instances of types)?

我想在编译时通过类型执行“static dispatching”。

具体来说,有一个函数族(按类型参数化),我想 select 基于参数类型的那个族(在编译时)的函数。

C11 中,可以使用 _Generic().

来做到这一点

例如,以下代码有效。

// gcc generic.c -o generic  &&  ./generic
#include <stdio.h>

void foo_int()   {  printf("%s\n", __func__);  }  // Arbitrary code to show that this works
void foo_float() {  printf("%s\n", __func__);  }  // Arbitrary code to show that this works
void foo_double(){  printf("%s\n", __func__);  }  // Arbitrary code to show that this works

#define foo_api0(VAL)   \
  _Generic(VAL,         \
    int:    foo_int,    \
    float:  foo_float,  \
    double: foo_double  \
  )()

int main(){
  foo_api0(2);
  foo_api0(4.f);
  foo_api0(8.);
}

但是,现在假设在宏 foo_api 中, 我不想传递 所需类型的值, 但我想传递 所需的类型本身 。 (为什么 的原因对于当前的讨论并不重要。假设这些原因存在。)

例如,而不是

  foo_api0(2);
  foo_api0(4.f);
  foo_api0(8.);

我想做

  foo_api1(int);
  foo_api1(float);
  foo_api1(double);

可以通过使用类型本身创建一个辅助变量(即 "witness" 类型)来实现:

#define foo_api1(TYPE)  ({  \
  TYPE witness;             \
  _Generic(witness,         \
    int:    foo_int,        \
    float:  foo_float,      \
    double: foo_double      \
  )();                      \
})

然后两个 API 都可以工作:

int main(){
  foo_api0(2);
  foo_api0(4.f);
  foo_api0(8.);

  foo_api1(int);
  foo_api1(float);
  foo_api1(double);
}

我的问题是:

有没有办法做到这一点而不使用这样的辅助变量? (也许 C 中有一个 macro/keyword 可以根据类型本身而不是该类型的变量来做事?)

例如,如果有这样的东西就好了:

#define foo_api1(TYPE)  ({  \
  _Generic(TYPE,            \
    int:    foo_int,        \
    float:  foo_float,      \
    double: foo_double      \
  )();                      \
})

to pass the desired type itself.

形成一个复合文字(TYPE){0}

#define foo_api1(TYPE)  \
  _Generic((TYPE){0},   \
    int:    foo_int,    \
    float:  foo_float,  \
    double: foo_double  \
  )()

int main(){
  foo_api1(int);
  foo_api1(float);
  foo_api1(double);
}

地址 评论:

形成复合文字作为指针:(TYPE *){0}

#define foo_api2(TYPE)   \
  _Generic((TYPE *){0},         \
    int *:    foo_int,    \
    float *:  foo_float,  \
    double *: foo_double  \
  )()