Jeśli potrzebujesz czegoś, co nie jest czymś w rodzaju wywołania funkcji, std::result_of
po 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..)>::type
i decltype(std::declval<F>()(std::declval<Args>()...)
polega na tym INVOKE
. Używanie declval
/ decltype
bezpośrednio, oprócz tego, że wpisywanie jest nieco dłuższe, jest poprawne tylko wtedy, gdy F
można je bezpośrednio wywołać (typ obiektu funkcji lub funkcja lub wskaźnik funkcji). result_of
dodatkowo obsługuje wskaźniki do funkcji składowych i wskaźniki do danych składowych.
Początkowo użycie declval
/ decltype
gwarantowało wyrażenie przyjazne dla SFINAE, podczas gdy std::result_of
może spowodować poważny błąd zamiast niepowodzenia dedukcji. Zostało to poprawione w C ++ 14: std::result_of
jest 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 F
s ‡ .
† 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_t
odniesiesz 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_of
nie 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
.
decltype
jest brzydszy, ale też potężniejszy.result_of
moż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_of
tutaj użyć :template <typename T, typename U> auto sum( T t, U u ) -> decltype( t + u );
jeśli argumenty mogą być typami arytmetycznymi (nie maF
takiej 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