Estaba jugando con auto
adentro std::pair
. En el siguiente código, f
se supone que la función devuelve una std::pair
de 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::pair
por 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::pair
que 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::pair
explí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 queint
sea 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.