Stavo giocando con auto
dentro std::pair
. Nel codice seguente, la funzione f
dovrebbe restituire un std::pair
tipo che dipende da un parametro template.
Un esempio funzionante:
ESEMPIO 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
}
Funziona con gcc 9.2, gcc 10.0, clang 9.0 e clang 10.0.
Successivamente, ho voluto scrivere esplicitamente il tipo restituito come a std::pair
motivi di chiarezza:
ESEMPIO 2
template <unsigned S>
std::pair<auto, auto> f()
{
if constexpr (S == 1)
return {1, 2};
/* ... */
}
Sia gcc 9.2 / 10.0 che clang 9.0 / 10.0 non sono riusciti a compilare questo.
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
Dall'ultimo messaggio di errore, gcc 9.2 sembra credere che std::pair<auto, auto>
sia un int
. Come può essere spiegato?
gcc 10.0
error: returning initializer list
Questo errore è comprensibile, tuttavia, mi aspettavo che il costruttore std::pair
fosse invocato o c'è qualcosa che mi manca qui?
clang 9.0 e 10.0
'auto' not allowed in template argument
excess elements in scalar initializer
no matching function for call to 'f'
Ok, a Clang non piace niente di tutto questo. Dal secondo messaggio di errore, sembra che Clang creda anche che sia il tipo restituito int
.
Infine, per correggere l'errore ottenuto compilando con gcc 10.0, ho deciso di restituire std::pair
esplicitamente un :
ESEMPIO 3
template <unsigned S>
std::pair<auto, auto> f()
{
if constexpr (S == 1)
return std::pair{1, 2};
/* ... */
}
clang 9.0 e 10.0
Come prima, ma con un ulteriore:
no viable conversion from returned value of type 'std::pair<int, int>' to function return type 'int'
Qui Clang pensa ancora che stiamo tornando un int
?
gcc 9.2
Come prima.
gcc 10.0
Funziona!
Immagino che alcune funzionalità debbano ancora essere implementate, o in una delle situazioni sopra descritte, c'è un compilatore che è giusto e l'altro sbagliato? Secondo me, l'esempio 2 dovrebbe funzionare. O non dovrebbe?