Info
-
Did you know about C++23 ispanstream - A strstream replacement using span as buffer?
Example
#include <span>
#include <spanstream>
#include <iostream>
int main() {
char input[] = "1 2 3";
std::ispanstream is{std::span<char>{input}};
int i1, i2, i3;
is >> i1 >> i2 >> i3;
std::cout << i1 << i2 << i3; // prints 123
}
Puzzle
- Can you implement to_tuple which converts (using ispanstream) given input into tuple of Ts...?
template<class... Ts, auto N>
[[nodiscard]] constexpr auto to_tuple(char (&input)[N]); // TODO
int main() {
using namespace boost::ut;
"to_tuple.ints"_test = [] {
char input[] = "1 2 3";
expect(std::tuple{1, 2, 3} == to_tuple<int, int, int>(input));
};
"to_tuple.floats"_test = [] {
char input[] = "1.2 2.3 3.4";
expect(std::tuple{1.2f, 2.3f, 3.4f} == to_tuple<float, float, float>(input));
};
"to_tuple.mix"_test = [] {
char input[] = "42 4.2";
expect(std::tuple{42, 4.2d} == to_tuple<int, double>(input));
};
}
Solutions
template<class T, class... Ts>
constexpr auto set_vals(auto tuple, auto& stream) {
T &val = std::get<std::tuple_size_v<decltype(tuple)> - sizeof...(Ts) - 1>(tuple);
stream >> val;
if constexpr (sizeof...(Ts) > 0) {
tuple = set_vals<Ts...>(tuple, stream);
}
return tuple;
}
template<class... Ts, auto N>
[[nodiscard]] constexpr auto to_tuple(char (&input)[N]) {
std::ispanstream stream{std::span<char>{input}};
return set_vals<Ts...>(std::tuple<Ts...>{}, stream);
}
namespace detail {
template <typename TArg>
[[nodiscard]] constexpr auto extract_arg(auto& stream) {
TArg arg{};
stream >> arg;
return arg;
}
} // namespace detail
template <class... Ts, auto N>
[[nodiscard]] constexpr auto to_tuple(char (&input)[N]) {
std::ispanstream stream{std::span<char>{input}};
return std::tuple{detail::extract_arg<Ts>(stream)...};
}
template <class... Ts, auto N>
[[nodiscard]] constexpr auto to_tuple(char (&input)[N]) {
std::tuple<Ts...> result;
auto& [...refs] = result;
std::ispanstream stream{input};
((stream >> refs), ...);
return result;
}
template<class... Ts, auto N>
[[nodiscard]] constexpr auto to_tuple(char (&input)[N]) {
constexpr auto extract = []<class T>(auto& input) -> T {
T t{};
input >> t;
return t;
};
std::ispanstream is{input};
return std::tuple{extract.template operator()<Ts>(is)...};
}
template <typename T> std::tuple<T> parse(std::ispanstream& is)
{
T t; is >> t;
return std::tuple<T>(std::move(t));
}
template <typename T, typename Arg, typename... Args>
std::tuple<T, Arg, Args...> parse(std::ispanstream& is)
{
T t; is >> t;
return std::tuple_cat(std::tuple<T>(std::move(t)),
parse<Arg, Args...>(is));
}
template<class... Ts, auto N>
[[nodiscard]] constexpr auto to_tuple(char (&input)[N])
{
std::ispanstream is{std::span<char>{input}};
return parse<Ts...>(is);
};
template<class... Ts, auto N>
[[nodiscard]] constexpr auto to_tuple(char (&input)[N]) {
auto stream = std::ispanstream{input};
auto values = std::tuple<Ts...>{};
std::apply([&](auto&... value) {
((stream >> value), ...);
}, values);
return values;
}
template<class... Ts, auto N>
[[nodiscard]] constexpr auto to_tuple(char (&input)[N]) {
std::ispanstream is{std::span{input}};
std::tuple<Ts...> return_values;
std::apply(
[&](Ts &... elements) {
(is >> ... >> elements);
},
return_values
);
return return_values;
};
template <class... Ts, auto N>
[[nodiscard]] constexpr auto to_tuple(char (&input)[N]) {
std::tuple<Ts...> t;
std::apply(
[&](Ts &...elements) {
(std::ispanstream{std::span{input}} >> ... >> elements);
},
t);
return t;
}
template<class... Ts, auto N>
[[nodiscard]] constexpr auto to_tuple(char (&input)[N]){
std::ispanstream is{std::span<char>{input}};
std::tuple<Ts...> t;
[&]<std::size_t... Indices>(std::index_sequence<Indices...>){
((is >> std::get<Indices>(t)), ...);
}(std::make_index_sequence<sizeof...(Ts)>());
return t;
}
template<class... Ts, auto N>
[[nodiscard]] constexpr auto to_tuple(char (&input)[N]) {
std::ispanstream is{std::span{input, N}};
std::tuple<Ts...> tp;
[&is, &tp]<size_t... I>(std::index_sequence<I...> const&) {
((is >> std::get<I>(tp)), ...);
}(std::index_sequence_for<Ts...>{});
return tp;
}
template<class... Ts, auto N>
[[nodiscard]] constexpr auto to_tuple(char (&input)[N]){
std::tuple<Ts...> my_tuple;
std::apply(
[&](Ts& ... args){
(std::ispanstream{std::span{input}} >> ... >> args);
}, my_tuple
);
return my_tuple;
}