вариационный шаблон с рекурсивным управлением

#c #templates #c 14

#c #шаблоны #c 14

Вопрос:

Мне нужна шаблонная функция, которая проверяет, есть ли первое значение среди последующих.


Я думал, что попробую что-то подобное, но это не сработало

 template<class T, class U>
bool is_in_set(const T amp;t, const U amp;u) {
  return t == u;
}

template<class T, class ...Args>
bool is_in_set(const T amp;t, Args...args) {
  return false || is_in_set(t, args...);
}
 

Он компилируется, но я получил следующее предупреждение warning C4717 : 'is_in_set' : recursive on all control paths, function will cause runtime stack overflow

Кто-нибудь может помочь мне исправить это и объяснить, почему это не работает?

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

1. Что вы подразумеваете под «это не работает»? Если он не компилируется, покажите сообщение об ошибке. Если он запускается, но выдает неверный вывод, покажите ввод и вывод.

2. Он компилируется, но я получил предупреждение о том warning C4717 : recursive on all control paths, function will cause runtime stack overflow , что я попытался запустить проблему, но произошло переполнение

3. Спасибо, но, пожалуйста, добавьте эту информацию в вопрос, а не в качестве комментария.

Ответ №1:

Начиная с C 17, вы можете написать эту функцию с помощью fold-выражения, что проще, чем писать рекурсивную функцию с базовым вариантом.

 template<class T, class ...Args>
bool is_in_set(T const amp; t, Args const amp; ...args) 
{
  return (... || (t == args));
}
 

И теперь вы можете назвать это так.

 is_in_set(1, 2, 3, 4);  // false
is_in_set(1, 2, 1, 4);  // true
 

Вот демонстрация


Учитывая ваш код, вы получаете предупреждение, потому что у вас бесконечная рекурсия в этой строке:

 return false || is_in_set(t, args...);  // infinite recursion here
 

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

Вы можете исправить это, присвоив второму аргументу имя и приняв остальные аргументы в качестве пакета параметров.

 template<class T, class U>
bool is_in_set(T const amp; t, U const amp;u) 
{
    return t == u;
}
  
template<class T, class U, class ...Args>
bool is_in_set(T const amp; t, U const amp; u, Args const amp;...args) 
{ 
  return is_in_set(t, u) || is_in_set(t, args...);
}
 

Вот демонстрация

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

1. Я работаю на c 14 в Visual Studio

2. @Linus Да, я только что увидел это, когда редактировал теги, поэтому я мог бы обновить ответ. Могу я спросить, почему вы все еще используете этот стандарт? Есть ли какие-либо внешние ограничения? Если нет, просто обновите свой компилятор.

3. На самом деле нет причин, это была настройка по умолчанию, я не так много знаю о разнице в стандарте, я попробую

4. Я не могу поверить, что это работает, я провел последние 2 дня, пытаясь понять это, что мне ввести, чтобы прочитать что-нибудь о 3 точках?

5. @Linus Отлично 🙂 Вы получите кучу дополнительных функций, которые можно использовать, если вы используете более современный стандарт, такой как C 17 или даже C 20. Я добавил решение, которое в любом случае работает и на C 14. ... Синтаксис представляет собой сложенное выражение. Я добавил ссылку для дальнейшего чтения.