Аргументы-вариадики с продолжением
От: Went  
Дата: 10.09.15 13:01
Оценка:
Здравствуйте. Допустим, есть функция
template<typename T>
void print(T a, int format)
{
  // Тут мы выводим а в консоль в формате format.
}


И, вооружившись новым стандартом, я решаюсь сделать чудесную variadic-style перегрузку:
template<typename T, typename... Args>
void print(T a0, Args... args, int format)
{
  print(a0);
  print(args..., format);
}


Но, увы, оно не пашет. Пишет, "не могу вывести аргументы для Args". Я, конечно, понимаю, можно вынести формат первым аргументом, но вот очень не хочется. Есть ли выход?
Re: Аргументы-вариадики с продолжением
От: watchmaker  
Дата: 10.09.15 13:17
Оценка: 9 (3)
Здравствуйте, Went, Вы писали:

W>Есть ли выход?


Есть костыль:
int get_format(int f) {
  return f;
}

template<typename T, typename... Args>
int get_format(T, Args... args) {
  return get_format(args...);
}
template<typename T, typename... Args>
void print(T a0, Args... args) {
  int format = get_format(args...);
  print(a0, format);
  print(args..., format);
}
Re[2]: Аргументы-вариадики с продолжением
От: uzhas Ниоткуда  
Дата: 10.09.15 14:04
Оценка: +1
Здравствуйте, watchmaker, Вы писали:

W>template<typename T, typename... Args>
W>void print(T a0, Args... args) {
W>  int format = get_format(args...);
W>  print(a0, format);
W>  print(args..., format);
W>}
W>


возможно, так лучше будет:
template<typename T, typename... Args>
void print(T a0, Args... args) {
  int format = get_format(args...);
  print(a0, format);
  print(args...);
}
Re: Аргументы-вариадики с продолжением
От: Molchalnik  
Дата: 10.09.15 15:13
Оценка:
Здравствуйте, Went, Вы писали:

W>Здравствуйте. Допустим, есть функция

W>
W>template<typename T>
W>void print(T a, int format)
W>{
W>  // Тут мы выводим а в консоль в формате format.
W>}
W>


W>И, вооружившись новым стандартом, я решаюсь сделать чудесную variadic-style перегрузку:

W>
W>template<typename T, typename... Args>
W>void print(T a0, Args... args, int format)
W>{
W>  print(a0);
W>  print(args..., format);
W>}
W>


W>Но, увы, оно не пашет. Пишет, "не могу вывести аргументы для Args". Я, конечно, понимаю, можно вынести формат первым аргументом, но вот очень не хочется. Есть ли выход?


попробуй для начала задать окончание рекурсии.
Re: Аргументы-вариадики с продолжением
От: ArtDenis Россия  
Дата: 10.09.15 15:16
Оценка:
Здравствуйте, Went, Вы писали:

W>...

W>Но, увы, оно не пашет. Пишет, "не могу вывести аргументы для Args". Я, конечно, понимаю, можно вынести формат первым аргументом, но вот очень не хочется. Есть ли выход?

Я бы не стал ставить format последним аргументом хотя бы из предпосылки, что так проще запутаться.
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[2]: Аргументы-вариадики с продолжением
От: Went  
Дата: 10.09.15 16:24
Оценка:
Здравствуйте, watchmaker, Вы писали:
W>Есть костыль.
Отличный костыль. Достаточно крпкий

В финале получилось вот что:
namespace print_impl {

inline const TextFormat& get_format(const TextFormat& format)
{
  // Нашли формат в хвосте - прекрасно
  return format;
}

inline const TextFormat& get_format()
{
  // Если формат не нашли - это дефолтный формат
  return text_format::normal;
}

template<typename T, typename... Args>
const TextFormat& get_format(const T& other, const Args&... rest)
{
  // Если после формата есть еще что-то - это явная ошибка
  static_assert(!std::is_same<TextFormat, T>::value, "text format is not last print argument");

  // Иначе ищем формат у хвоста
  return get_format(rest...);
}

} // print_impl

inline String print(const TextFormat& format)
{
  // Печатаем ничто не важно каким форматом
  return "";
}

template<typename T, typename... Args>
String print(const T& a0, const Args&... args)
{
  // Печатаем много чего, формат добываем из последнего аргумента, если такой есть
  return print(a0, print_impl::get_format(a0, args...)) + print(args...);
}


Всяческие перегрузки функции print на два аргумента (что пишем и опционально формат) реализованы отдельно.
Re[2]: Аргументы-вариадики с продолжением
От: Went  
Дата: 10.09.15 16:26
Оценка:
Здравствуйте, Molchalnik, Вы писали:
M>попробуй для начала задать окончание рекурсии.
А разве верхняя функция ей не является?
Re[2]: Аргументы-вариадики с продолжением
От: Went  
Дата: 10.09.15 16:29
Оценка:
Здравствуйте, ArtDenis, Вы писали:
AD>Я бы не стал ставить format последним аргументом хотя бы из предпосылки, что так проще запутаться.
Он опционален. Да и вообще, так уж сделано
Re[3]: Аргументы-вариадики с продолжением
От: Molchalnik  
Дата: 16.09.15 17:44
Оценка:
Здравствуйте, Went, Вы писали:

W>Здравствуйте, Molchalnik, Вы писали:

M>>попробуй для начала задать окончание рекурсии.
W>А разве верхняя функция ей не является?

имхо нет.
Re[3]: Аргументы-вариадики с продолжением
От: Molchalnik  
Дата: 16.09.15 17:49
Оценка:
Здравствуйте, Went, Вы писали:
думаю, концом рекурсии была бы функция с шаблонными параметрами template<typename T, typename Last>
Re[4]: Аргументы-вариадики с продолжением
От: Went  
Дата: 16.09.15 18:29
Оценка:
Здравствуйте, Molchalnik, Вы писали:

M>Здравствуйте, Went, Вы писали:

M>думаю, концом рекурсии была бы функция с шаблонными параметрами template<typename T, typename Last>
Зачем? Если учесть, что в рассматриваемом примере аргумент format обязателен (нет значения по умолчанию, нет перегрузки без оного), то добавление такой функции создаст возможность допустить ошибку, закончив функцию не-интом.
Или в этой функции подразумевается static_assert(false)?
Re[5]: Аргументы-вариадики с продолжением
От: Molchalnik  
Дата: 18.09.15 09:01
Оценка:
Здравствуйте, Went, Вы писали:

W>Здравствуйте, Molchalnik, Вы писали:


M>>Здравствуйте, Went, Вы писали:

M>>думаю, концом рекурсии была бы функция с шаблонными параметрами template<typename T, typename Last>
W>Зачем? Если учесть, что в рассматриваемом примере аргумент format обязателен (нет значения по умолчанию, нет перегрузки без оного), то добавление такой функции создаст возможность допустить ошибку, закончив функцию не-интом.
W>Или в этой функции подразумевается static_assert(false)?

Блин. Ты спрашиваешь других или пытаешься убедить себя в своей правоте? Вот решение твоей задачи. Без всяких там костылей вроде статик ассертов


template<typename T> void print_internal(T a) {
  (void)a;
}

template<typename T>
void print(T a, int format)
{
  // Тут мы выводим а в консоль в формате format.
  (void)a;
  (void)format;
  printf("\nDone!!!");
}

template<typename T, typename... Args>
void print(T a0, Args... args)
{
  print_internal(a0);
  print(args...);
}

struct StType {
  int x;
  long y;
};

int main(int argc, char *argv[])
{
    StType st_x;
    print("f", 3);
    print("f", (long)5, 3);
    print("f",8,st_x,(long)3, (int)5);
    //print("f",8,st_x,(long)3, st_x); //если раскомментировать, то эта строка даст ошибку
}


вывод программы:

Done!!!
Done!!!
Done!!!


Ты НЕ сделал окончание рекурсии грамотно — и поэтому у тебя или не работает, или костыли в виде ассертов.

Здесь ЕСТЬ правильное окончание рекурсии — и здесь и работает, и вызвать функцию print с последним аргументом, отличным от int НЕВОЗМОЖНО без ошибок компиляции.

И, что важно, использовать подсказку ты не захотел. Мне нужно было потратить своё время, сделать этот пример самому, для того, чтобы ты стал квалифицированнее и зарабатывал больше. Потому что ты повёл себя излишне самоуверенно и не подумал над ответом. Когда ты станешь получать больше, ты будешь присылать мне роялти?


P.s. Кстати, если задать второе окончание рекурсии,
void print() {};
, то этому коду станет наплевать на последний аргумент, пройдёт любой. А пока окончание рекурсии существует только для последнего аргумента типа int, поэтому и работает только для int'а последнего, на этом и основано решение.
Отредактировано 18.09.2015 9:08 Molchalnik . Предыдущая версия . Еще …
Отредактировано 18.09.2015 9:02 Molchalnik . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.