Якщо вам потрібен тип чогось, що не є чимось на зразок виклику функції, 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...)>
суворо перевершує. Це чіткіше, коротше і правильно † підтримує більше F
s ‡ .
† Якщо тільки ви не використовуєте його в контексті, коли ви не хочете дозволити вказівникам членам, то це
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
без використання в'яжучих чи лямбда