Tema representativo de entrevista

Entrevista de código: ¿Cómo funciona el pack indexing en C++26 y cuándo deberías proporcionar un fallback?

CodingIntermedio
Equipo editorial de Offer.ccPublicado Actualizado

Pregunta

Una biblioteca variádica debe leer el N-ésimo tipo o valor sin dejar de compilar en compiladores que no tienen soporte para C++26. Explica la sintaxis de pack indexing, las restricciones, los modos de fallo, la detección de características y un diseño de fallback.

Planteamiento y alcance

Una biblioteca genérica debe leer un elemento en una posición fija de un pack de tipos o un pack de argumentos de función utilizando el pack indexing de C++26, permitiendo que las cadenas de herramientas más antiguas sigan compilando. Explica el indexado de packs de expresiones, el indexado de packs de tipos, las restricciones de índice, la detección de características y las implementaciones de compatibilidad.

Esto evalúa las reglas del lenguaje y los fallbacks de ingeniería; no asumas que todas las versiones de compilador ya implementan esta característica.

Qué evalúa el entrevistador

  • Si distingues el indexado de packs de expresiones del especificador de pack-indexing para packs de tipos.
  • Si sabes que el índice debe ser una constante en tiempo de compilación y no puede exceder el tamaño del pack.
  • Si utilizas __cpp_pack_indexing para la detección de capacidades en lugar de adivinar a partir del nombre del compilador.
  • Si un fallback recursivo o con tuple preserva el contrato de la API.

Preguntas para clarificar

  1. ¿Estás indexando un pack de valores, un pack de tipos o un pack de parámetros de plantilla?
  2. ¿El índice es una constante en tiempo de compilación o un entero en tiempo de ejecución?
  3. ¿Qué compiladores, modos de lenguaje y versiones de CI son compatibles?
  4. ¿Un índice fuera de rango debe fallar en una restricción o deben verificarlo los llamadores?
  5. ¿El fallback debe preservar los diagnósticos y la complejidad, además del comportamiento?

Una respuesta en 30 segundos

“El pack indexing de C++26 selecciona un elemento de un pack de expresiones con un índice constante; un pack de tipos utiliza un especificador de pack-indexing. El índice debe ser una constante en tiempo de compilación y no puede estar fuera de rango. Un entero en tiempo de ejecución sigue requiriendo un arreglo, una tupla o una tabla de despacho. Detectaría __cpp_pack_indexing, usaría la sintaxis directa cuando esté disponible, emplearía recursión u operaciones de tupla en compiladores más antiguos y probaría límites y comportamientos de API idénticos”.

Diseño paso a paso

1. Separar las dos formas

El indexado de packs de expresiones selecciona un valor a partir de los argumentos de una función; el indexado de packs de tipos selecciona un tipo a partir de los parámetros de plantilla. Ambos trasladan la selección posicional a la instanciación de plantillas y reducen la recursión escrita a mano, pero su sintaxis y su uso posterior difieren.

2. Exigir evaluación en tiempo de compilación

El índice es una expresión constante en el contexto de un parámetro de plantilla que no es de tipo. Un entero en tiempo de ejecución no puede reemplazarlo. Si se requiere una selección en tiempo de ejecución, materializa el pack como una tupla, arreglo o tabla de funciones y despacha en tiempo de ejecución.

cpp
template <std::size_t I, class... Ts>
using type_at = Ts...[I];

template <std::size_t I, class... Ts>
constexpr decltype(auto) value_at(Ts&&... values) {
  return values...[I];
}

3. Manejar packs vacíos y fuera de rango

Un pack vacío no tiene ningún elemento indexable, y un índice igual o superior al tamaño del pack no es válido. Una plantilla pública debería rechazarlo tempranamente con una restricción requires que mantenga el índice por debajo del tamaño del pack. Las pruebas deben cubrir llamadas vacías, con el primer elemento, con el último y fuera de rango.

4. Usar la detección de características

cppreference registra la macro de prueba de características __cpp_pack_indexing con el valor 202311L. Comprueba la macro junto con el modo de lenguaje y utiliza el CI del compilador cuando sea necesario; una cadena de versión del compilador por sí sola no constituye un contrato de capacidad del lenguaje.

5. Diseñar un fallback para cadenas de herramientas más antiguas

Sin C++26, un pack de tipos puede usar plantillas recursivas o una utilidad de selección de tipos de tuplas; un pack de valores puede formar primero una tupla y llamar a una utilidad de acceso posicional. Preserva la misma restricción de límites y compila ambas rutas en CI.

6. Evaluar la API y los diagnósticos

El pack indexing directo acorta la implementación, pero debe mantenerse detrás de una API estable. Documenta el modo estándar requerido, haz que los diagnósticos indiquen el índice y el tamaño del pack, y evalúa el tiempo de compilación y el código generado para ambas rutas en lugar de limitarte a comparar líneas de código fuente.

Respuesta modelo de alta calidad

“Primero identificaría la entidad indexada. El indexado de packs de expresiones de C++26 selecciona un valor, mientras que un pack de tipos usa el especificador de pack-indexing; el índice es una constante en tiempo de compilación, por lo que los packs vacíos y fuera de rango deberían fallar en el límite de la restricción. Detectaría __cpp_pack_indexing; usaría la sintaxis directa en cadenas de herramientas compatibles y recursión, tuple_element y get en las más antiguas detrás de la misma API. Un índice en tiempo de ejecución necesita una tupla o una tabla de despacho. Las pruebas cubren casos vacíos, límites, fuera de rango, ambos modos de lenguaje y ambas implementaciones”.

Errores comunes

  • Usar un entero en tiempo de ejecución como índice de plantilla → el lenguaje requiere una constante → usar una tupla, arreglo o tabla de despacho.
  • Comprobar únicamente __cplusplus el soporte de características depende del estado de implementación → comprobar __cpp_pack_indexing y CI.
  • Dejar los límites implícitos → los errores aparecen en lo profundo de la instanciación → restringir la interfaz de forma temprana.
  • Implementar solo packs de tipos → las llamadas con packs de valores todavía necesitan recursión → probar ambas formas por separado.
  • Cambiar la semántica en el fallback → las cadenas de herramientas se comportan de forma diferente → compartir restricciones, pruebas y la API estable.

Preguntas de seguimiento y respuestas

¿Puede el pack indexing resolver el indexado en tiempo de ejecución?

No. Requiere una constante en tiempo de compilación. La selección en tiempo de ejecución necesita una tupla, un arreglo, una tabla de funciones u otra estructura de despacho en tiempo de ejecución.

¿Por qué añadir una restricción requires?

El lenguaje finalmente rechazará un índice fuera de rango, pero una restricción explícita proporciona diagnósticos de interfaz más tempranos y claros, y permite que el fallback exponga el mismo contrato.

¿Es el fallback recursivo siempre más lento?

No. El código en tiempo de ejecución puede optimizarse al mismo resultado, mientras que la profundidad de plantillas, el tiempo de compilación y los diagnósticos pueden diferir. Valida con la matriz de soporte y benchmarks en lugar de juzgar por la longitud de la sintaxis.

Fuentes públicas

Preguntas relacionadas

Herramienta de entrevista relacionada

Usa Captura para un ejercicio de código

Captura el problema y luego aborda en orden las restricciones, la solución, el código, los casos extremos y la complejidad.

Ver la herramienta