Есть ли ярлык для decltype

В этот ответ Я написал код C ++ 17:

cout << accumulate(cbegin(numbers), cend(numbers), decay_t<decltype(numbers[0])>{});

Это получило некоторые негативные комментарии о природе ассоциации типов в C ++, и мне грустно говорить, что я согласен с 🙁

decay_t<decltype(numbers[0])>{} это очень сложный способ получить:

Инициализированный нулем тип элемента numbers

Можно ли сохранить связь с типом numbers‘элементы, но не набирать как 30 символов, чтобы получить его?

РЕДАКТИРОВАТЬ:

У меня есть много ответов, включая обертку для любого accumulate или для извлечения типа из numbers[0], Проблема в том, что они требуют, чтобы читатель перешел во вторичное местоположение, чтобы прочитать решение, которое не менее сложно, чем код инициализации decay_t<decltype(numbers[0])>{},

Единственная причина, по которой мы должны сделать больше, чем это: decltype(numbers[0]) Это потому что оператор индекса массива возвращает ссылку:

ошибка: неверное приведение выражения rvalue типа int к типу int&’

Интересно, что по отношению к decltypeаргумент:

Если имя объекта заключено в скобки, оно рассматривается как обычное выражение lvalue

Тем не мение, decltype((numbers[0])) до сих пор просто ссылка на элемент numbers, Таким образом, в конечном итоге эти ответы могут быть как можно ближе к упрощению этой инициализации 🙁

4

Решение

Хотя я всегда хотел бы написать вспомогательную функцию согласно @Barry,
если numbers — это стандартный контейнер, он будет экспортировать тип value_type, так что вы можете сэкономить немного сложности:

cout << accumulate(cbegin(numbers), cend(numbers), decltype(numbers)::value_type());

Продвигаясь дальше, мы могли бы определить эту функцию шаблона:

template<class Container, class ElementType = typename Container::value_type>
constexpr auto element_of(const Container&, ElementType v = 0)
{
return v;
}

что дает нам это:

cout << accumulate(cbegin(numbers), cend(numbers), element_of(numbers, 0));
2

Другие решения

Личные предпочтения: я нахожу decay_t, decltype а также declval танцы довольно раздражающие и трудно читать.

Вместо этого я бы использовал дополнительный уровень косвенности через черту типа value_t<It> и нулевая инициализация через init = R{}

template<class It>
using value_t = typename std::iterator_traits<It>::value_type;

template<class It, class R = value_t<It>>
auto accumulate(It first, It last, R init = R{}) { /* as before */ }
2

Я думаю, что лучшее, что вы можете сделать, это просто где-то это учесть:

template <class It, class R = std::decay_t<decltype(*std::declval<It>())>>
R accumulate(It first, It last, R init = 0) {
return std::accumulate(first, last, init);
}

std::cout << accumulate(cbegin(numbers), cend(numbers));

Или в целом:

template <class Range, class T =
std::decay_t<decltype(*adl_begin(std::declval<Range&&>()))>>
T accumulate(Range&& range, T init = 0) {
return std::accumulate(adl_begin(range), adl_end(range), init);
}

cout << accumulate(numbers);

где adl_begin это версия begin() что составляет ADL.

Конечно, технически у нас все еще есть все, что вы пытались избежать раньше … но, по крайней мере, теперь вам никогда не придется смотреть на это снова?

1
По вопросам рекламы [email protected]