Seleção genérica (C11)

Use a palavra-chave _Generic para escrever um código que seleciona uma expressão em tempo de compilação com base no tipo do argumento. É semelhante à sobrecarga no C++, em que o tipo do argumento seleciona a função chamada. Nesse caso, o tipo do argumento seleciona qual expressão avaliar.

Por exemplo, a expressão _Generic(42, int: "integer", char: "character", default: "unknown"); avalia o tipo de 42 procura o tipo correspondente, int, na lista. Ele o encontra e retorna "integer".

Sintaxe

generic-selection:
_Generic(assignment-expression, assoc-list)

assoc-list:
association
assoc-list, association

association:
type-name : assignment-expression
default : assignment-expression

O primeiro assignment-expression é chamado de expressão controladora. O tipo da expressão controladora é determinado no momento da compilação e comparado com assoc-list para encontrar a expressão a ser avaliada e retornada. A expressão controladora não é avaliada. Por exemplo, _Generic(intFunc(), int: "integer", default: "error"); não resulta em uma chamada em runtime para intFunc.

Quando o tipo da expressão de controle é determinado, const, volatile e restrict são removidos antes de corresponder a assoc-list.

As entradas nas assoc-list que não são escolhidas não são avaliadas.

Restrições

  • O assoc-list não pode especificar o mesmo tipo mais de uma vez.
  • O assoc-list não pode especificar tipos compatíveis uns com os outros, como uma enumeração e o tipo subjacente dessa enumeração.
  • Se uma seleção genérica não tiver um padrão, a expressão controladora precisará ter apenas um nome de tipo compatível na lista de associações genéricas.

Exemplo

Uma maneira de usar _Generic é em uma macro. O arquivo de cabeçalho <tgmath.h> usa _Generic para chamar a função matemática correta, dependendo do tipo de argumento. Por exemplo, a macro para cos mapeia uma chamada com um float para cosf, enquanto mapeia uma chamada com um duplo complexo para ccos.

O exemplo a seguir mostra como escrever uma macro que identifica o tipo do argumento que você passa para ela. Ele produzirá "unknown" se nenhuma entrada em assoc-list corresponder à expressão de controle:

// Compile with /std:c11

#include <stdio.h>

/* Get a type name string for the argument x */
#define TYPE_NAME(X) _Generic((X), \
      int: "int", \
      char: "char", \
      double: "double", \
      default: "unknown")

int main()
{
    printf("Type name: %s\n", TYPE_NAME(42.42));

    // The following would result in a compile error because 
    // 42.4 is a double, doesn't match anything in the list, 
    // and there is no default.
    // _Generic(42.4, int: "integer", char: "character"));
}

/* Output:
Type name: double
*/

Requisitos

Compilar com /std:c11.

O SDK do Windows 10.0.20348.0 (versão 2104) ou posterior. Consulte o SDK do Windows para baixar o SDK mais recente. Para obter instruções sobre como instalar e usar o SDK para desenvolvimento C11 e C17, consulte Instalar o suporte C11 e C17 no Visual Studio.

Confira também

/std (Especificar a versão padrão da linguagem)
Matemática do tipo genérico