C11: Использование `_Generi c ()` (или чего-то еще) для самих типов (не экземпляров типов)? - PullRequest
1 голос
/ 14 апреля 2020

Я хочу сделать " stati c диспетчеризация " во время компиляции через типы.

В частности, есть семейство функций (параметризованных по типу), и я хочу чтобы выбрать функцию из этого семейства (во время компиляции) на основе типа аргумента.

В 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);

Этого можно добиться, используя сам тип для создания вспомогательной переменной (ie. «Свидетель» типа):

#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, который может делать вещи, основываясь на самом типе, а не на переменной этого типа?)

Например, было бы неплохо иметь что-то вроде:

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

1 Ответ

3 голосов
/ 14 апреля 2020

для передачи самого нужного типа.

Форма составной литерал : (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);
}

По адресу @ Eri c Postpischil комментарий:

Формирование составного литерала в виде указателя: (TYPE *) {0}

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