Estaba jugando con autoadentro std::pair. En el siguiente código, fse supone que la función devuelve una std::pairde los tipos que dependen de un parámetro de plantilla.
Un ejemplo de trabajo:
EJEMPLO 1
template <unsigned S>
auto f()
{
if constexpr (S == 1)
return std::pair{1, 2}; // pair of ints
else if constexpr (S == 2)
return std::pair{1.0, 2.0}; // pair of doubles
else
return std::pair{0.0f, 0.0f}; // pair of floats
}
Esto funciona con gcc 9.2, gcc 10.0, clang 9.0 y clang 10.0.
A continuación, quería escribir explícitamente el tipo de retorno como a std::pairpor razones de claridad:
EJEMPLO 2
template <unsigned S>
std::pair<auto, auto> f()
{
if constexpr (S == 1)
return {1, 2};
/* ... */
}
Tanto gcc 9.2 / 10.0 como clang 9.0 / 10.0 no pudieron compilar esto.
gcc 9.2
error: invalid use of 'auto'
error: template argument 1 is invalid // first argument (auto) of std::pair
error: template argument 2 is invalid // second argument (auto) of std::pair
error: cannot convert '<brace-enclosed initializer list>' to 'int' in return
Desde el último mensaje de error, gcc 9.2 parece creer que std::pair<auto, auto>es un int. ¿Cómo se puede explicar esto?
gcc 10.0
error: returning initializer list
Este error es comprensible, sin embargo, esperaba std::pairque se invocara al constructor o ¿hay algo que me falta aquí?
Clang 9.0 y 10.0
'auto' not allowed in template argument
excess elements in scalar initializer
no matching function for call to 'f'
Ok, a clang no le gusta nada de esto. Desde el segundo mensaje de error, parece que clang también cree que el tipo de retorno es int.
Finalmente, para corregir el error obtenido al compilar con gcc 10.0, decidí devolver std::pairexplícitamente:
EJEMPLO 3
template <unsigned S>
std::pair<auto, auto> f()
{
if constexpr (S == 1)
return std::pair{1, 2};
/* ... */
}
Clang 9.0 y 10.0
Igual que antes, pero con un adicional:
no viable conversion from returned value of type 'std::pair<int, int>' to function return type 'int'
Aquí el sonido metálico todavía piensa que estamos regresando un int?
gcc 9.2
Igual que antes.
gcc 10.0
¡Funciona!
Supongo que algunas características aún tienen que implementarse, o en una de las situaciones descritas anteriormente, ¿hay un compilador correcto y el otro incorrecto? En mi opinión, el ejemplo 2 debería funcionar. ¿O no debería?

auto x = {1, 2};funciona, pero solo si todos los tipos son iguales.int. No es queintsea un marcador de posición en los mensajes de error; el compilador realmente piensa que es unint. (Para aclarar esto, gcc probablemente debería haber dicho "asumiendo int" en algún momento).std::pair __f{1,2};funciona.std::optional f() { return 4; }trabajo.