Jeśli potrzebujesz czegoś, co nie jest czymś w rodzaju wywołania funkcji, std::result_ofpo prostu nie ma zastosowania. decltype()może podać typ dowolnego wyrażenia.
Jeśli ograniczymy się tylko do różnych sposobów określania typu zwracanego wywołania funkcji (między std::result_of_t<F(Args...)>i decltype(std::declval<F>()(std::declval<Args>()...)), to istnieje różnica.
std::result_of<F(Args...) definiuje się jako:
Jeśli wyrażenie
INVOKE (declval<Fn>(), declval<ArgTypes>()...)jest poprawnie sformułowane, gdy jest traktowane jako nieoceniony operand (klauzula 5), typ elementu członkowskiego typedef powinien nazwać typ w decltype(INVOKE (declval<Fn>(), declval<ArgTypes>()...));
przeciwnym razie, nie będzie żadnego typu elementu członkowskiego.
Różnica między result_of<F(Args..)>::typei decltype(std::declval<F>()(std::declval<Args>()...)polega na tym INVOKE. Używanie declval/ decltypebezpośrednio, oprócz tego, że wpisywanie jest nieco dłuższe, jest poprawne tylko wtedy, gdy Fmożna je bezpośrednio wywołać (typ obiektu funkcji lub funkcja lub wskaźnik funkcji). result_ofdodatkowo obsługuje wskaźniki do funkcji składowych i wskaźniki do danych składowych.
Początkowo użycie declval/ decltypegwarantowało wyrażenie przyjazne dla SFINAE, podczas gdy std::result_ofmoże spowodować poważny błąd zamiast niepowodzenia dedukcji. Zostało to poprawione w C ++ 14: std::result_ofjest teraz wymagane, aby było przyjazne dla SFINAE (dzięki temu artykułowi ).
Tak więc zgodny kompilator C ++ 14 std::result_of_t<F(Args...)>jest zdecydowanie lepszy. Jest wyraźniejszy, krótszy i poprawnie † obsługuje więcej Fs ‡ .
† Chyba że używasz go w kontekście, w którym nie chcesz zezwalać na wskaźniki do członków, więc
std::result_of_todniesiesz sukces w przypadku, gdy możesz chcieć, aby to się nie udało.
‡ Z wyjątkami. Chociaż obsługuje wskaźniki do członków, result_ofnie będzie działać, jeśli spróbujesz utworzyć wystąpienie nieprawidłowego identyfikatora typu . Obejmowałyby one funkcję zwracającą funkcję lub przyjmującą typy abstrakcyjne według wartości. Dawny.:
template <class F, class R = result_of_t<F()>>
R call(F& f) { return f(); }
int answer() { return 42; }
call(answer); // nope
Prawidłowe użycie byłoby result_of_t<F&()>, ale jest to szczegół, o którym nie musisz pamiętać decltype.
decltypejest brzydszy, ale też potężniejszy.result_ofmoże być używany tylko dla typów, które są wywoływalne i wymaga typów jako argumentów. Na przykład nie możeszresult_oftutaj użyć :template <typename T, typename U> auto sum( T t, U u ) -> decltype( t + u );jeśli argumenty mogą być typami arytmetycznymi (nie maFtakiej funkcji , którą możesz zdefiniowaćF(T,U)do reprezentowaniat+u. Dla typów zdefiniowanych przez użytkownika możesz. W ten sam sposób (tak naprawdę nie bawiłem się). że wywołania metodresult_of