About a general reader / writer for STL-Structures, 
Difference between en4 and en5, changed 437 character(s)
Hi everybody,↵

I started to implement very general functions to use in programming competitions, such as this general reader/writer for C++ tuple, containers, and basic types~:↵

~~~~~↵
#include <iostream>↵
#include <tuple>↵
#include <type_traits>↵
#include <utility>↵
#include <vector>↵
using namespace std;↵


template <typename T>↵
constexpr bool is_tuple = false;↵

template<typename ... types>↵
constexpr bool is_tuple<tuple<types...>> = true;↵

template<typename A, typename B>↵
constexpr bool is_tuple<pair<A, B>> = true;↵


template<typename T> struct IsContainer { ↵
typedef typename remove_const<T>::type test_type;↵
template<typename A> static constexpr bool test(A* pt, decltype(pt->begin())* = nullptr, decltype(pt->end())* = nullptr) ↵
{ return is_same<decltype(pt->begin()),typename A::iterator>::value && is_same<decltype(pt->end()),typename A::iterator>::value; }↵
template<typename A> static constexpr bool test(...) { return false; }↵
static constexpr bool value = test<test_type>(nullptr);↵
};↵

template<typename T>↵
constexpr bool is_container = IsContainer<T>::value;↵


template <typename T>↵
constexpr bool is_string = is_same<T, string>::value;↵

template<typename>↵
struct to_mutable { };↵

template<typename... Ts>↵
struct to_mutable<tuple<Ts...>> {↵
    using type = tuple<typename remove_cv<Ts>::type...>;↵
};↵

template<typename... Ts>↵
struct to_mutable<pair<Ts...>> {↵
    using type = pair<typename remove_cv<Ts>::type...>;↵
};↵


string readline() { string value; getline(cin, value); return value; }↵

template<typename T, typename ...Args> typename enable_if<!is_tuple<T> && (!is_container<T> || is_string<T>), T>::type read() {↵
T value;↵
cin >> value;↵
return value;↵
}↵

template<typename T, typename ...Args> typename enable_if<is_tuple<T>, T>::type read(Args ...args);↵

template<typename T, typename ...Args> typename enable_if<is_container<T>, T>::type read(size_t N, Args... args) { ↵
T container;↵
for(size_t i = 0;i < N;i++) { ↵
*inserter(container, container.end()) = read<typename T::value_type>(args...);↵
}↵
return container;↵
}
;

template<typename T> typename enable_if<is_container<T> && !is_string<T>, T>::type read() { ↵
size_t N = read<size_t>();↵
return read<T>(N);↵
}↵

template<typename X, size_t I = 0, typename ...Args, typename enable_if<is_tuple<X>, X>::type* = nullptr>↵
typename enable_if<I == tuple_size<X>::value, typename to_mutable<X>::type>::type read_tuple(Args... args) { return typename to_mutable<X>::type(); }↵

template<typename X, size_t I = 0, typename ...Args, typename enable_if<is_tuple<X>, X>::type* = nullptr>↵
typename enable_if<I < tuple_size<X>::value, typename to_mutable<X>::type>::type read_tuple(Args... args) {↵
auto tmp = read<typename tuple_element<I, typename to_mutable<X>::type>::type>(args...);↵
typename to_mutable<X>::type value = read_tuple<X, I + 1>(args...);↵
get<I>(value) = tmp;↵
return value;↵
}↵

template<typename T, typename ...Args> typename enable_if<is_tuple<T>, T>::type read(Args... args) { return read_tuple<T>(args...); }↵

template<typename T, typename ...Args> typename enable_if<is_container<T>, T>::type read(size_t N, Args... args) { ↵
T container;↵
for(size_t i = 0;i < N;i++) { ↵
*inserter(container, container.end()) = read<typename T::value_type>(args...);↵
}↵
return container;↵
}↵


void flush() { cout << flush; }↵

void writesp() { cout << " "; }↵
void writeln() { cout << "\n"; }↵

template<typename T> void writesp(const T& value);↵
template<typename T> void writeln(const T& value);↵

template<typename T, typename enable_if<!is_container<T> && !is_tuple<T>, T>::type* = nullptr> ↵
void write(const T& value) { cout << value; }↵
void write(const string& value) { cout << value; }↵
void write(const char* value) { cout << value; }↵

template<typename T, typename enable_if<is_container<T>, T>::type* = nullptr> void writerow(const T& value) { ↵
typedef typename T::const_iterator It; ↵
for(It it = value.begin();it != value.end();it++) { writesp(*it); }↵
}↵

template<size_t I = 0, typename X, typename enable_if<is_tuple<X>, X>::type* = nullptr>↵
typename enable_if<I == tuple_size<X>::value, void>::type writerow(const X& t) {}↵
template<size_t I = 0, typename X, typename enable_if<is_tuple<X>, X>::type* = nullptr>↵
typename enable_if<I < tuple_size<X>::value, void>::type writerow(const X& t) { writesp(get<I>(t)); writerow<I + 1>(t); }↵

template<typename T, typename enable_if<is_container<T>, T>::type* = nullptr> void writecol(const T& value) { ↵
typedef typename T::const_iterator It; ↵
for(It it = value.begin();it != value.end();it++) { writeln(*it); }↵
}↵

template<size_t I = 0, typename X, typename enable_if<is_tuple<X>, X>::type* = nullptr>↵
typename enable_if<I == tuple_size<X>::value, void>::type writecol(const X& t) {}↵
template<size_t I = 0, typename X, typename enable_if<is_tuple<X>, X>::type* = nullptr>↵
typename enable_if<I < tuple_size<X>::value, void>::type writecol(const X& t) { writesp(get<I>(t)); writerow<I + 1>(t); }↵

template<typename T, typename enable_if<!is_container<typename T::value_type> && !is_tuple<typename T::value_type>, T>::type* = nullptr> void write(const T& value) { writerow(value); }↵
template<typename T, typename enable_if<is_tuple<T>, T>::type* = nullptr> void write(const T& value) { writerow(value); }↵

template<typename T> void write2d(const T& value) {↵
typedef typename T::const_iterator It; ↵
for(It it = value.begin();it != value.end();it++) { writeln(*it); }↵
}↵

template<typename T, typename enable_if<is_container<typename T::value_type>, T>::type* = nullptr> void write(const T& value) { write2d(value); }↵
template<typename T, typename enable_if<is_tuple<typename T::value_type>, T>::type* = nullptr> void write(const T& value) { write2d(value); }↵

template<typename T> void writesp(const T& value) { write(value); writesp(); }↵
template<typename T> void writeln(const T& value) { write(value); writeln(); }↵


void fast_io() { ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); }↵


int main() {↵
fast_io();↵

int nbRows = read<int>(), nbCols = read<int>();↵
auto grid = read<vector<vector<int>>>(nbRows, nbCols);↵

write(grid);↵
return 0;↵
}↵
~~~~~↵

The final goal is to write the minimum amount of code to describe an algorithm to the machine, by having a big library of algorithms I can use. I have a little tool that selects in the final code only the parts I need.↵

To use `write`, it is sufficient to call it with your variable. If you want to print a newline, or a space at the end, use `writeln` or `writesp`.↵

To use `read`, give the type you want to read between `<` and `>`. If you want to read a container (a STL-structure with `begin()` and `end()`), you can give sizes to the function, otherwise it'll read the size from the standard input.↵

This code works with many types, for examples, `map<string, vector<pair<int, double>>>`, but be aware that some structures (like `priority_queue`) aren't supported because they don't have `begin()` or `end()`. Keep also in mind that if you give sizes as arguments to your functions, they will be interpreted by order of depth in the template definition, but things like `pair<vector<int>, vector<int>>` will not work with given (different) sizes.↵

If enough people are interested in such implementations, I'll continue to publish them on my blog.↵
If you find any bug, or if you think another structure should be able to be read/written, please leave a comment.↵

Thank you for reading.

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
en6 English Arturgo 2019-11-04 23:22:36 0 (published)
en5 English Arturgo 2019-11-03 14:42:03 437 (saved to drafts)
en4 English Arturgo 2019-11-01 14:05:22 13 Tiny change: 'Thank you !' -> 'Thank you for reading.' (published)
en3 English Arturgo 2019-11-01 14:04:49 82
en2 English Arturgo 2019-11-01 13:57:47 585
en1 English Arturgo 2019-11-01 13:45:15 7096 Initial revision (saved to drafts)