TL;DW: kompilator Rust nadaje funkcjom różne typy, nawet jeśli ich nagłówek jest identyczny. Dzięki temu generyczny kod wywolujący taką funkcję może ją inline’ować.
Funkcje mogą otrzymać ten sam typ, jeżeli ich kod maszynowy (po optymalizacji) jest taki sam.
C++ rozróżnia funkcje na podstawie samego nagłówka i w związku z tym musi generować bardziej uniwersalne wywołania poprzez wskaźnik (bo wiele funkcji może mieć tę samą listę parametrów i typ zwracany, ale różne implementacje).
Przypomina mi to dawną prezentację o tym że JS jest szybsze niż C. Ktoś w tej prezentacji specjalnie wstawił volatile do zmiennej w C.
W tym przypadku kiedy usuniesz noinline, dostaniesz to samo co dostajesz kiedy użyjesz lambdy. Więc kompilator sobie z tym radzi. Pewnie jakby użył constexpr/eval to pewnie uzyskiwałby informacje, czemu się w ten sposób nie kompiluje. Nie znam się, więc powiem, że w C++ rozwiązano to odwrotnie.
W wersji Rust też jest
inline(never)
. Tutaj nie chodzi o to, że w C++ się nie da. Da się. Tylko trzeba czasem użyć wiedzy tajemnej, żeby osiągnąć ten sam efekt.Zresztą wystarczy porównać wygląd i ilość kodu w wersji pod Rust i C++. Widać jak na dłoni, gdzie autor biblioteki standardowej musiał walczyć z ograniczeniami języka. ;-)
Wiem, że w Rust też jest. Uznaje to za przypadek brzegowy w którym ktoś wyszukał problem (którego nie ma).
W Rust też trzeba użyć wiedzy tajemnej. Bo taki wynik nie był jawnie zadeklarowany. Wyszedł taki w tym przykładzie. Nie wiadomo czy taki wyjdzie, kiedy będzie bardziej skomplikowany program. Kompilatory przecież też maja ograniczenia (chyba do 3 warstw abstrakcji).
W C++ masz deklarację, że chcesz taki wynik i dostaniesz błąd, kiedy nie można takiego osiągnąć.