#c #templates #c 11 #decltype
#c #шаблоны #c 11 #decltype
Вопрос:
Я только что видел этот действительно хороший доклад Бориса Джейбса Rock Hard: C Evolving. В разделе доклада, посвященном универсальному программированию более высокого порядка, он говорит, что ниже приведен пример функции, которая является более универсальной в отношении ее возвращаемого типа и приводит к меньшим перегрузкам шаблонных функций
template <typename Func>
auto deduce(const Func amp; f) -> decltype(f())
{..}
Это, однако, может быть реализовано с использованием простого синтаксиса шаблона следующим образом
template <typename Func>
Func deduce(const Func amp; f)
{..}
поэтому я думаю, что выбранный пример на самом деле не показывает уникальную силу decltype
. Может кто-нибудь привести пример такого более поучительного использования decltype
?
Комментарии:
1. Нет. Первый пример означает, что
deduce<Func>(f)
возвращает типFunc
результата. Второй пример означает, чтоdeduce<Func>(f)
возвращаетFunc
. Вы видите разницу?2. Ааа, извините, я пропустил лишнее
()
внутри аргумента todecltype
. Моя ошибка.
Ответ №1:
Ваши подозрения неверны.
void f() { }
Теперь deduce(amp;f)
имеет тип void
, но при вашей перезаписи у него есть тип void(*)()
. В любом случае, везде, где вы хотите получить тип выражения или объявления, вы используете decltype
(обратите внимание на тонкую разницу между этими двумя. decltype(x)
не обязательно совпадает с decltype((x))
).
Например, вполне вероятно, что ваша реализация стандартной библиотеки где-то содержит такие строки, как
using size_t = decltype(sizeof(0));
using ptrdiff_t = decltype((int*)0 - (int*)0);
using nullptr_t = decltype(nullptr);
Определение правильного возвращаемого типа add
было сложной проблемой на протяжении всего прошлого C . Теперь это простое упражнение.
template<typename A, typename B>
auto add(A constamp; a, B constamp; b) -> decltype(a b) { return a b; }
Мало что известно о том, что вы можете использовать decltype
до ::
и в имени псевдодеструктора
// has no effect
(0).~decltype(0)();
// it and ite will be iterators into an initializer list
auto x = { 1, 2, 3 };
decltype(x)::iterator it = x.begin(), ite = x.end();
Комментарии:
1. Не могли бы вы, пожалуйста, немного объяснить это:
(0).~decltype(0)();
? Боюсь, я этого не понимаю.2. (0).~decltype(0)(); не компилируется с gcc, но компилируется с clang . Полезно, если 0 заменяется объектом класса, это будет явным вызовом собственного деструктора объекта. Так что это допустимо (по крайней мере, с помощью clang), чтобы шаблон мог работать с объектами класса, а также с int и т. Д. См. godbolt.org/z/M4NNfN
Ответ №2:
std::for_each(c.begin(), c.end(), [](decltype (c.front()) val){val*=2;});
Автоматическое преобразование value_type контейнера c не может быть выполнено без decltype .
Комментарии:
1. Это невозможно сделать, только если вы используете лямбды, учитывая, что они не являются полиморфными (тем не менее, будем надеяться, что они есть в C y). Если вы использовали объект полиморфной функции, он будет выведен автоматически.
Ответ №3:
Одно место, где я его использую, — это то, где мне нужно создать переменную, которая должна иметь тот же тип, что и другая переменная. но я не уверен, останется ли в будущем тип тем же или нет.
void foo(int a)//maybe in future type of a changed
{
decltype(a) b;
//do something with b
}