Якщо вам потрібен тип чогось, що не є чимось на зразок виклику функції, std::result_ofпросто не застосовується. decltype()може дати вам тип будь-якого виразу.
Якщо ми обмежимось лише різними способами визначення типу повернення виклику функції (між std::result_of_t<F(Args...)>і decltype(std::declval<F>()(std::declval<Args>()...)), то є різниця.
std::result_of<F(Args...) визначається як:
Якщо вираз
INVOKE (declval<Fn>(), declval<ArgTypes>()...)добре сформований, коли трактується як неоцінений операнд (п. 5), тип typededef тип повинен decltype(INVOKE (declval<Fn>(), declval<ArgTypes>()...));
інакше назвати тип , не повинен бути тип члена.
Різниця між result_of<F(Args..)>::typeі decltype(std::declval<F>()(std::declval<Args>()...)все в цьому полягає INVOKE. Використання declval/ decltypeбезпосередньо, окрім того, що вводиться дещо довше, є дійсним лише за умови Fпрямого виклику (тип об’єкта функції або функція або покажчик функції). result_ofдодатково підтримує покажчики на функції членів та покажчики на дані членів.
Спочатку використання declval/ decltypeгарантоване SFINAE-дружнє вираження, тоді як std::result_ofможе призвести до вашої помилки замість відрахування. Це було виправлено в C ++ 14: std::result_ofтепер потрібно бути SFINAE-дружнім (завдяки цій роботі ).
Отже, на відповідному компіляторі C ++ 14 std::result_of_t<F(Args...)>суворо перевершує. Це чіткіше, коротше і правильно † підтримує більше Fs ‡ .
† Якщо тільки ви не використовуєте його в контексті, коли ви не хочете дозволити вказівникам членам, то це
std::result_of_tбуде досягати успіху у випадку, коли ви, можливо, хочете, щоб він не вийшов.
‡ За винятками. Хоча він підтримує покажчики на членів, result_ofне буде працювати, якщо ви спробуєте інстанціювати недійсний ідентифікатор типу . До них можна віднести функцію, яка повертає функцію або приймає абстрактні типи за значенням. Наприклад:
template <class F, class R = result_of_t<F()>>
R call(F& f) { return f(); }
int answer() { return 42; }
call(answer); // nope
Правильне використання було б result_of_t<F&()>, але це деталь, яку вам не потрібно пам’ятати decltype.
decltypeце гірше, але й потужніше.result_ofможе використовуватися лише для типів, які можна викликати, і для цього потрібні типи як аргументи. Наприклад, ви не можете використовуватиresult_ofтут:template <typename T, typename U> auto sum( T t, U u ) -> decltype( t + u );якщо аргументи можуть бути арифметичними типами (немає такої функціїF, яку можна визначитиF(T,U)представлятиt+u. Для визначених користувачем типів ви могли б. Так само (я не дуже грав з цим) що дзвінки до методів учасників важко обійтисяresult_ofбез використання в'яжучих чи лямбда