Можно ли вставить дополнительную операцию в выражение сгиба?
В C++17 доступно сложенное выражение, поэтому для вывода аргументов мы могли бы использовать
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 ответа
Что если я хотел бы использовать выражение свертывания, добавляющее дополнительный символ '\n' к каждому элементу, чтобы получить следующие результаты?
Вы можете использовать мощность оператора запятой
((std::cout << args << std::endl), ...);
или, как предложил Квентин (спасибо), и, как вы просили, вы можете просто использовать \n
вместо std::endl
(чтобы избежать многократного смыва потока)
((std::cout << args << '\n'), ...);
Это решение @nm без грубой глобальной жадности 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';});
и это работает.
Я знаю, что оператор запятой, вероятно, самый простой способ сделать это, но для полноты вот кое-что, что я придумал, главным образом потому, что я хотел показать свое небольшое обобщение 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';});
}
Этот метод может использоваться в сценариях, где нам нужно фиксировать значение выражения сгиба, а не его побочные эффекты. Оператор запятой менее полезен в таких контекстах.