Можно ли вставить дополнительную операцию в выражение fold?

В C++17 доступно выражение fold, поэтому для вывода аргументов мы могли бы использовать

#define EOL '\n'

template<typename ...Args>
void output_argus(Args&&... args) 
{
    (cout << ... << args) << EOL;
}


int main()
{
    output_argus(1, "test", 5.6f);
}

с выводом
1test5.6

Что, если я хочу использовать выражение fold, добавляя дополнительный символ '\n' к каждому элементу, чтобы получить следующие результаты?

1
test
5.6

Это вообще возможно? Если да, то как?


person r0ng    schedule 08.11.2018    source источник


Ответы (3)


Что если я хочу использовать выражение fold, добавляя дополнительный символ '\n' к каждому элементу, чтобы получить следующие результаты?

Вы можете использовать силу оператора запятой

 ((std::cout << args << std::endl), ...);

или, как предложил Квентин (спасибо) и как вы просили, вы можете просто использовать \n вместо std::endl (чтобы избежать многократного сброса потока)

 ((std::cout << args << '\n'), ...); 
person max66    schedule 08.11.2018
comment
std::endl совершенно излишен, OP просто хочет новую строку. - person Quentin; 09.11.2018

Это решение @n.m. без грубого глобального жадного operator<<.

template<class Os>
struct chain_stream {
  Os& stream;
  template<class Rhs,
    std::enable_if_t<std::is_same_v<Os&, decltype(std::declval<Os&>() << std::declval<Rhs>())>, bool> =true
  >
  friend chain_stream<Os> const& operator<<( chain_stream<Os> const& os, Rhs&& rhs ) {
    os.stream << std::forward<Rhs>(rhs);
    return os;
  }
  // iomanipulator:
  friend chain_stream<Os> const& operator<<( chain_stream<Os> const& os, Os&(*rhs)(Os&) ) {
    os.stream << rhs;
    return os;
  }
  template<class Rhs,
    std::enable_if_t<
      std::is_same_v< std::result_of_t< Rhs&&(chain_stream const&) >, void >
      || std::is_same_v< std::result_of_t< Rhs&&(chain_stream const&) >, Os& >,
    bool> =true
  >
  friend chain_stream<Os> const& operator<<( chain_stream<Os> const& os, Rhs&& rhs ) {
    std::forward<Rhs>(rhs)( os );
    return os;
  }
};

теперь мы можем сделать:

 (chain_stream{std::cout} << ... << [&](auto& x){x << args << '\n';});

и это работает.

person Yakk - Adam Nevraumont    schedule 09.11.2018

Я знаю, что оператор запятая, вероятно, самый простой способ сделать это, но для полноты картины я придумал вот что, главным образом потому, что хотел показать свое небольшое обобщение iomanip. Стандартная библиотека iomanips — это функции. Существует перегрузка <<, которая принимает указатель на функцию. Я расширил это для произвольных вызываемых объектов, которые принимают и возвращают потоки по ссылке.

template <class Stream, class Func>
auto operator << (Stream& s, Func f) -> 
        std::enable_if_t<std::is_same_v<decltype(f(s)), Stream&>, Stream&>
{
    return f(s);
}

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

template<typename ...Args>
void output_args(Args&&... args)
{
     (std::cout << ... << [&](auto& x)->auto&{return x << args << '\n';});
}

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

person n. 1.8e9-where's-my-share m.    schedule 08.11.2018
comment
Бесплатный жадный оператор << выглядит грубо. Вместо этого я бы пометил один из типов (функцию или поток). - person Yakk - Adam Nevraumont; 09.11.2018
comment
@Yakk-AdamNevraumont, идея состоит в том, чтобы функциональные объекты работали точно так же, как обычные старые функции. Простые старые функции уже работают как манипуляторы ввода-вывода. - person n. 1.8e9-where's-my-share m.; 09.11.2018
comment
да, но перегрузка << для них имеет определенные типы. Ваш будет работать над вещами, совершенно не связанными с ostreams. Возможно случайно, в худшем случае вызовет сбои сборки из-за ошибок, не связанных с sfinae. - person Yakk - Adam Nevraumont; 09.11.2018
comment
@Yakk-AdamNevraumont Да, это легко ограничить ostreams, не делайте этого здесь, чтобы уменьшить многословие. - person n. 1.8e9-where's-my-share m.; 09.11.2018