Grałem około z autow std::pair. W poniższym kodzie funkcja fpowinna zwracać std::pairtypy zależne od parametru szablonu.
Przykład roboczy:
PRZYKŁAD 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
}
Działa to z gcc 9.2, gcc 10.0, clang 9.0 i clang 10.0.
Następnie chciałem jawnie napisać typ zwracany std::pairze względów przejrzystości:
PRZYKŁAD 2
template <unsigned S>
std::pair<auto, auto> f()
{
if constexpr (S == 1)
return {1, 2};
/* ... */
}
Zarówno gcc 9.2 / 10.0, jak i clang 9.0 / 10.0 nie skompilowały tego.
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
Po ostatnim komunikacie o błędzie gcc 9.2 wydaje się wierzyć, że std::pair<auto, auto>jest to int. Jak można to wyjaśnić?
gcc 10.0
error: returning initializer list
Ten błąd jest zrozumiały, ale spodziewałem się, że std::pairzostanie wywołany konstruktor, czy też czegoś mi brakuje?
klang 9.0 i 10.0
'auto' not allowed in template argument
excess elements in scalar initializer
no matching function for call to 'f'
Ok, clangowi się to nie podoba. Na podstawie drugiego komunikatu o błędzie wydaje się, że clang uważa również, że typem zwrotu jest int.
Wreszcie, aby naprawić błąd uzyskany podczas kompilacji z gcc 10.0, postanowiłem zwrócić std::pairjawnie:
PRZYKŁAD 3
template <unsigned S>
std::pair<auto, auto> f()
{
if constexpr (S == 1)
return std::pair{1, 2};
/* ... */
}
klang 9.0 i 10.0
Tak jak poprzednio, ale z dodatkowym:
no viable conversion from returned value of type 'std::pair<int, int>' to function return type 'int'
Tutaj klang nadal myśli, że wracamy int?
gcc 9.2
Tak samo jak ostatnio.
gcc 10.0
To działa!
Wydaje mi się, że niektóre funkcje wciąż muszą zostać zaimplementowane lub w jednej z opisanych powyżej sytuacji, czy istnieje kompilator, który jest poprawny, a drugi źle? Moim zdaniem przykład 2 powinien działać. A może nie?