Stavo giocando con autodentro std::pair. Nel codice seguente, la funzione fdovrebbe restituire un std::pairtipo 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::pairmotivi 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::pairfosse 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::pairesplicitamente 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?