Можно ли вставить дополнительную операцию в выражение сгиба? - PullRequest
0 голосов
/ 09 ноября 2018

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

#define EOL '\n'

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


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

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

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

1
test
5.6

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

Ответы [ 3 ]

0 голосов
/ 09 ноября 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';});
}

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

0 голосов
/ 09 ноября 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';});

и все работает.

0 голосов
/ 09 ноября 2018

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

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

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

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

 ((std::cout << args << '\n'), ...); 
...