Шаблоны переменных — Рекурсивная функция — Последний элемент переменной

#c #variadic-templates #typetraits

#c #переменные-шаблоны #признаки типов

Вопрос:

У меня есть следующий код с шаблоном переменной, скопированным из:https://www.youtube.com/watch?v=iWvcoIKSaoc В41:30

 auto sum() { return 0; }

template<typename Head, typename... Tail>
auto sum(Head head, Tail... tail)
{
    return head sum(tail...);
}

int main() {
    cout<< sum(1,2.4) << endl;
    //cout<< sum("hello ", "world") << endl;
    return 0;
}
  

У меня есть два вопроса:
1. Здесь требуется функция sum (), чтобы я мог возвращать значение для void, переданного при обработке последнего элемента переменной — Возможно ли избежать написания этой функции sum () и иметь ту же функциональность?

  1. Возврат целого числа ‘0’ из функции sum () ограничивает использование всего шаблона целыми числами — Могу ли я расширить тот же шаблон для объединения строк?

Спасибо

Комментарии:

1. Означает ли тег C 14, что вы не хотите слышать о C 17-кратных выражениях?

2. Нет — Я согласен с C 17

Ответ №1:

В дополнение к ответу @GuillaumeRacicot я предпочитаю заканчивать рекурсию, if constexpr которая является c 17 функцией.

 template<typename Head, typename Second, typename... Tail>
auto sum(Head head, Second second, Tail... tail)
{ 
    if constexpr(sizeof...(tail) > 0)
      return head   sum(second, tail...);
    return head   second;
}
  

Вы также можете рассмотреть выражения fold:

 template<typename ...Pack>
auto sum(Pack... args) {
    return (args   ...);
}
  

Комментарии:

1. Если вы работаете на C 17, вы могли бы также использовать выражение fold

Ответ №2:

Хитрость заключается в том, чтобы никогда не разрешать пустые sum() вызовы и рассматривать sum(last) как последнюю рекурсию:

 template<typename Last>
auto sum(Last last) {
    return last;
}

template<typename Head, typename Second, typename... Tail>
auto sum(Head head, Second second, Tail... tail)
{
    return head   sum(second, tail...);
}

int main() {
    cout<< sum(1,2.4) << endl;
    cout<< sum("hello ", "world") << endl;
    return 0;
}
  

Живой пример

Ответ №3:

  1. Здесь требуется sum() функция, чтобы я мог возвращать значение для void переданного при обработке последнего элемента переменной — Возможно ли избежать написания этой sum() функции и иметь ту же функциональность?

Для каждой рекурсии требуется условие остановки. При типичном использовании рекурсии с шаблонами переменных (например, в этом коде) условием остановки является другая перегрузка основного шаблона. Таким образом, вы не можете полностью избавиться от этого.

Вы, конечно, можете заменить условие остановки другим. Возможно, этот, который также будет работать для суммирования вещей, которые не могут быть сконструированы по умолчанию:

 template <class T>
auto sum(T last) { return last; }
  

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

  1. Возврат целого числа ‘0’ из sum() функции ограничивает использование всего шаблона целыми числами — Могу ли я расширить тот же шаблон для объединения строк?

Нет, потому что не шаблонная функция не знает, с каким типом имели дело предыдущие рекурсивные вызовы. Это можно решить, используя условие остановки «последнего элемента», которое я предложил выше.

Комментарии:

1. Как работает решение с return {}; ? Я не могу заставить это работать: ideone.com/vrCXSb

2. @mch Конечно, это была ошибка с моей стороны. Исправлено.