2
\$\begingroup\$

The problem:

In C++ arrays and SequenceContainers http://en.cppreference.com/w/cpp/concept/SequenceContainer (std::array, std::deque, std::vector) are necessarily zero-indexed. However, from the semantical point of view, elements of an array may be assigned a completely other range of indexes. One common example is the need to store a 1-indexed array in a 0-indexed container. (I remember having to operate on an arbitrarily-indexed arrays, however)

Solutions to the above problems include:

  • remembering to skew the index by a given constant each time such an array is indexed – this leads to lots of code like vec[n-1] or sth like that – but this approach is tedious and error-prone (it’s easy to forget this -1 and instead type vec[n], oops);
  • Defining a class for such an array that would have a method like some_type &operator [] (unsigned n) {return m_arr[n-1];} – but this can often be quite overkillish;
  • The crude approach: Forget about the fact that arrays are 0-indexed; treat them as if they were 1-indexed and never use index 0. This approach is, however, well – crude, and it will fail with arbitrarily-indexed arrays.

The proposed solution:

I thought I’d write a wrapper for SequenceContainers that would differ from standard containers only in that its operator[] and the at functions would skew their arguments by a given offset. I wrote two versions of this wrapper: one, when the offset is determined compile-time as a template argument, and the other one, when it can be modified run-time. I believe that both are needed.

The usage is simple, as shown in a trivial example of calculating lengths of Collatz sequence for the first 100 initial values: ( https://en.wikipedia.org/wiki/Collatz_conjecture ) (sorry for the naive algorithm)

#include "shiftsc.hpp"

using namespace std;

using element = unsigned;
using length = unsigned;

length compute_length(element n)
  {return n == 1 ? 1 : (1 + compute_length(n % 2 == 0 ? n / 2 : n * 3 + 1));}

int main()
{
  constexpr element max_element = 100;

  // one-indexed std::array<length, max_element>
  shifted_SequenceContainer<array<length, max_element>, 1> Collatz_lengths;
  // or for short: shifted_array<length, max_element, 1> Collatz_lengths;

  for(element i = 1; i <= max_element; i++)
    Collatz_lengths[i] = compute_length(i);
}

Seen working: http://ideone.com/Xy8A2U

(I’ll provide a use-case for the variation with run-time offset later, in a separate question – I have an idea for yet another wrapper that would need this functionality to operate)

The problems with the solution:

Before I present You the code, I have to write down a few issues I can see with this code I don’t know how to fix… (inb4 close votes: they don’t make the code broken!)

  • The length of the code. Ikr, it is hilarious. There’s very little I can do, however: writing containers requires defining a TON of different methods, and although the code of most of them is trivial, their sheer amount is what makes this code 453 lines long. I thought about different ‘solutions” to this issue, none of which worked: • defining a base class for container wrappers – impossible b/c of the incompatibility of virtual with templates (couldn’t allow overloading methods like template <class Iterator> void assign (Iterator it, Iterator jt); • defining repetitive methods and the whole class in terms of macros; this did work and did shorten the code, but IMO made it utterly unreadable, so I gave up.
  • std::array can be initialized with a braced-init-list; unfortunately, shifted_SequenceContainer<std::array</*...*/>/*...*/> cannot. And I don’t really have many ideas how to fix this. https://stackoverflow.com/questions/40599052/how-to-write-a-wrapper-for-stdarrays-list-initialization-constructor https://stackoverflow.com/questions/40599829/how-to-pass-a-braced-init-list-to-stdarray-s-constructor
  • The naming. Ikr, shifted_SequenceContainer breaks all naming conventions… But what can I do? The concept is called SequenceContainer, so if I changed that, I’d cease referring to this concept… It’s called SequenceContainer not sequence_container so a name like shifted_sequence_container won’t fit, and a name like ShiftedSequenceContainer would be incongruent with the naming of standard containers – after all, std::unordered_map is called unordered_map and not UnorderedMap.

The code:

Enough of the (lengthy) preface, here comes the actual code:

#ifndef GAAZKAM_SHIFTSC_H
#define GAAZKAM_SHIFTSC_H

#include <utility>
#include <initializer_list>
#include <stdexcept>
#include <cstddef>
#include <array>
#include <vector>
#include <deque>

// Known problems: syntax like shifted_array<int, 4, 7> arr({1,2,3,4}) wont work

// With static offset

// Container must satisfy SequenceContainer
template<class Container, typename Container::difference_type Offset>
class shifted_SequenceContainer
{
public:
  using value_type = typename Container::value_type;
  using reference = typename Container::reference;
  using const_reference = typename Container::const_reference;
  using pointer = typename Container::pointer;
  using const_pointer = typename Container::const_pointer;
  using iterator = typename Container::iterator;
  using const_iterator = typename Container::const_iterator;
  using reverse_iterator = typename Container::reverse_iterator;
  using const_reverse_iterator = typename Container::const_reverse_iterator;
  using difference_type = typename Container::difference_type;
  using size_type = typename Container::size_type;

  using container_type = Container;

  // Must be public; otherwise the user mayn’t access e.g. vector::reserve,
  // which might be needed for optimization
  Container cont;

  static constexpr typename Container::difference_type offset = Offset;

  explicit shifted_SequenceContainer() {}
  shifted_SequenceContainer(shifted_SequenceContainer const &that)
    : cont(that.cont) {}
  shifted_SequenceContainer(shifted_SequenceContainer &&that)
    : cont(std::move(that.cont)) {}
  explicit shifted_SequenceContainer(Container const &that) : cont(that) {}
  explicit shifted_SequenceContainer(Container &&that) : cont(that) {}
  shifted_SequenceContainer &operator = (shifted_SequenceContainer const &that)
    {cont = that.cont; return *this;}
  shifted_SequenceContainer &operator = (shifted_SequenceContainer &&that)
    {cont = std::move(that.cont); return *this;}
  shifted_SequenceContainer &operator = (Container const &that)
    {cont = that; return *this;}
  shifted_SequenceContainer &operator = (Container &&that)
    {cont = std::move(that); return *this;}
  shifted_SequenceContainer
    (size_type n, value_type const &val = value_type())
    : cont(n, val) {}
  template<class Iterator> shifted_SequenceContainer(Iterator it, Iterator jt)
    : cont(it, jt) {}
  shifted_SequenceContainer(std::initializer_list<value_type> init) 
    : cont(init) {}
  shifted_SequenceContainer &operator = (std::initializer_list<value_type> init)
    {cont = init; return *this;}
  void assign(size_type n, value_type const &val) {return cont.assign(n, val);}
  template<class Iterator> void assign(Iterator it, Iterator jt)
    {return cont.assign(it, jt);}
  void assign(std::initializer_list<value_type> init)
    {return cont.assign(init);}
  void swap(shifted_SequenceContainer &that) {return cont.swap(that.cont);}
  friend void swap
    (shifted_SequenceContainer &lhs, shifted_SequenceContainer &rhs)
    {return swap(lhs.cont, rhs.cont);}

  friend bool operator ==
    (shifted_SequenceContainer const &lhs, shifted_SequenceContainer const &rhs)
    {return lhs.cont == rhs.cont;}
  friend bool operator != 
    (shifted_SequenceContainer const &lhs, shifted_SequenceContainer const &rhs)
    {return lhs.cont != rhs.cont;}
  friend bool operator <
    (shifted_SequenceContainer const &lhs, shifted_SequenceContainer const &rhs)
    {return lhs.cont < rhs.cont;}
  friend bool operator <=
    (shifted_SequenceContainer const &lhs, shifted_SequenceContainer const &rhs)
    {return lhs.cont <= rhs.cont;}
  friend bool operator >
    (shifted_SequenceContainer const &lhs, shifted_SequenceContainer const &rhs)
    {return lhs.cont > rhs.cont;}
  friend bool operator >=
    (shifted_SequenceContainer const &lhs, shifted_SequenceContainer const &rhs)
    {return lhs.cont >= rhs.cont;}

  constexpr size_type size() const {return cont.size();}
  constexpr size_type max_size() const {return cont.max_size();}
  void resize(size_type n) {return cont.resize(n);}
  void resize(size_type n, value_type const &val) {return cont.resize(n, val);}
  constexpr bool empty() const {return cont.empty();} 

  template<class ...Args> iterator emplace(const_iterator pos, Args &&...args)
    {return cont.emplace(pos, std::move(args...));}
  template<class ...Args> void emplace_front(Args &&...args)
    {return cont.emplace_front(std::move(args...));}
  template<class ...Args> void emplace_back(Args &&...args)
    {return cont.emplace_back(std::move(args...));}
  iterator insert(const_iterator pos, value_type const &val)
    {return cont.insert(pos, val);}
  iterator insert(const_iterator pos, value_type &&val)
    {return cont.insert(pos, std::move(val));}
  iterator insert(const_iterator pos, size_type n, value_type const &val)
    {return cont.insert(pos, n, val);}
  template<class Iterator> void insert(iterator pos, Iterator it, Iterator jt)
    {return cont.insert(pos, it, jt);}
  iterator insert(const_iterator pos, std::initializer_list<value_type> init)
    {return cont.insert(pos, init);}
  void push_front(value_type const &val) {return cont.push_front(val);}
  void push_front(value_type &&val) {return cont.push_front(std::move(val));}
  void push_back(value_type const &val) {return cont.push_back(val);}
  void push_back(value_type &&val) {return cont.push_back(std::move(val));}

  void clear() {return cont.clear();}
  iterator erase(const_iterator pos) {return cont.erase(pos);}
  iterator erase(const_iterator it, const_iterator jt)
    {return cont.erase(it, jt);}
  void pop_front() {return cont.pop_front();}
  void pop_back() {return cont.pop_back();}

  iterator begin() {return cont.begin();}
  constexpr const_iterator begin() const {return cont.begin();}  
  constexpr const_iterator cbegin() const {return cont.cbegin();}
  iterator end() {return cont.end();}
  constexpr const_iterator end() const {return cont.end();}
  constexpr const_iterator cend() const {return cont.cend();}
  reverse_iterator rbegin() {return cont.rbegin();}
  constexpr const_reverse_iterator rbegin() const {return cont.rbegin();}
  constexpr const_reverse_iterator crbegin() const {return cont.crbegin();}
  reverse_iterator rend() {return cont.rend();}
  constexpr const_reverse_iterator rend() const {return cont.rend();}
  constexpr const_reverse_iterator crend() const {return cont.crend();}
  reference front() {return cont.front();}
  constexpr const_reference front() const {return cont.front();}
  reference back() {return cont.back();}
  constexpr const_reference back() const {return cont.back();}

  // Here things actually start to change
  reference operator[] (difference_type pos)
    {return cont.operator[](pos-offset);}
  constexpr const_reference operator[] (difference_type pos) const
    {return cont.operator[](pos-offset);}
  reference at (difference_type pos)
    {if(pos-offset<0) throw std::out_of_range(""); return cont.at(pos-offset);}
  constexpr const_reference at (difference_type pos) const
    {if(pos-offset<0) throw std::out_of_range(""); return cont.at(pos-offset);}

  // Additionally let’s provide these ones:
  iterator find(difference_type pos)
    {return cont.begin()+(pos-offset);}
  constexpr const_iterator find(difference_type pos) const
    {return cont.cbegin()+(pos-offset);}
};

template
  <class T, std::size_t N, typename std::array<T, N>::difference_type offset>
using shifted_array = shifted_SequenceContainer<std::array<T, N>, offset>;

template<class T, typename std::vector<T>::difference_type offset>
using shifted_vector = shifted_SequenceContainer<std::vector<T>, offset>;

template<class T, typename std::deque<T>::difference_type offset>
using shifted_deque = shifted_SequenceContainer<std::deque<T>, offset>;

// With dynamic offset

// Container must satisfy SequenceContainer
template<class Container>
class dynshifted_SequenceContainer
{
public:
  using value_type = typename Container::value_type;
  using reference = typename Container::reference;
  using const_reference = typename Container::const_reference;
  using pointer = typename Container::pointer;
  using const_pointer = typename Container::const_pointer;
  using iterator = typename Container::iterator;
  using const_iterator = typename Container::const_iterator;
  using reverse_iterator = typename Container::reverse_iterator;
  using const_reverse_iterator = typename Container::const_reverse_iterator;
  using difference_type = typename Container::difference_type;
  using size_type = typename Container::size_type;

  using container_type = Container;

  // Must be public; otherwise the user mayn’t access e.g. vector::reserve,
  // which might be needed for optimization
  Container cont;
  difference_type offset = 0;

  explicit dynshifted_SequenceContainer() {}
  dynshifted_SequenceContainer(dynshifted_SequenceContainer const &that)
    : cont(that.cont), offset(that.offset) {}
  template<typename Container::difference_type StaticOffset>
  dynshifted_SequenceContainer
    (shifted_SequenceContainer<Container, StaticOffset> const &that)
    : cont(that.cont), offset(StaticOffset) {}
  dynshifted_SequenceContainer(dynshifted_SequenceContainer &&that)
    : cont(std::move(that.cont)), offset(that.offset) {}
  template<typename Container::difference_type StaticOffset>
  dynshifted_SequenceContainer
    (shifted_SequenceContainer<Container, StaticOffset> &&that)
    : cont(std::move(that.cont)), offset(StaticOffset) {}
  explicit dynshifted_SequenceContainer
    (Container const &that, difference_type off = difference_type{}) 
    : cont(that), offset(off) {}
  explicit dynshifted_SequenceContainer
    (Container &&that, difference_type off = difference_type{})
    : cont(that), offset(off) {}
  dynshifted_SequenceContainer &operator =
    (dynshifted_SequenceContainer const &that)
    {offset = that.offset; cont = that.cont; return *this;}
  template<typename Container::difference_type StaticOffset>
  dynshifted_SequenceContainer &operator =
    (shifted_SequenceContainer<Container, StaticOffset> const &that)
    {cont = that.cont; offset = StaticOffset; return *this;}
  dynshifted_SequenceContainer &operator = (dynshifted_SequenceContainer &&that)
    {offset = that.offset; cont = std::move(that.cont); return *this;}
  template<typename Container::difference_type StaticOffset>
  dynshifted_SequenceContainer &operator = 
    (shifted_SequenceContainer<Container, StaticOffset> &&that)
    {{cont = std::move(that.cont); offset = StaticOffset; return *this;}}
  dynshifted_SequenceContainer &operator = (Container const &that)
    {cont = that; return *this;}
  dynshifted_SequenceContainer &operator = (Container &&that)
    {cont = std::move(that); return *this;}
  explicit dynshifted_SequenceContainer
  (
    size_type n,
    value_type const &val = value_type(),
    difference_type offset = 0
  )
    : cont(n, val), offset(offset) {}
  explicit dynshifted_SequenceContainer(size_type n, difference_type offset)
    : cont(n, value_type{}), offset(offset) {}
  template<class Iterator> dynshifted_SequenceContainer
    (Iterator it, Iterator jt, difference_type offset = 0)
    : cont(it, jt), offset(offset) {}
  dynshifted_SequenceContainer
    (std::initializer_list<value_type> init, difference_type offset = 0)
    : cont(init) {}
  dynshifted_SequenceContainer &operator =
    (std::initializer_list<value_type> init)
    {cont = init; return *this;}
  void assign(size_type n, value_type const &val) {return cont.assign(n, val);}
  void assign(size_type n, value_type const &val, difference_type offset)
    {this->offset = offset; return cont.assign(n, val);}
  template<class Iterator> void assign(Iterator it, Iterator jt)
    {return cont.assign(it, jt);}
  template<class Iterator>
  void assign(Iterator it, Iterator jt, difference_type offset)
    {this.offset = offset; return cont.assign(it, jt);}
  void assign(std::initializer_list<value_type> init)
    {return cont.assign(init);}
  void assign(std::initializer_list<value_type> init, difference_type offset)
    {this.offset = offset; return cont.assign(init);}
  void swap(dynshifted_SequenceContainer &that)
    {std::swap(this->offset, that.offset); return cont.swap(that.cont);}
  friend void swap
    (dynshifted_SequenceContainer &lhs, dynshifted_SequenceContainer &rhs)
    {std::swap(lhs.offset, rhs.offset); return swap(lhs.cont, rhs.cont);}

  // I provide all those overloads despite the implicit conversion for
  // optimisation: implicit conversion is always linear, while those
  // overloads may sometimes evaluate in constant
  friend bool operator ==
  (
    dynshifted_SequenceContainer const &lhs,
    dynshifted_SequenceContainer const &rhs
  )
    {return lhs.cont == rhs.cont;}
  template<typename Container::difference_type StaticOffset>
  friend bool operator ==
  (
    shifted_SequenceContainer<Container, StaticOffset> const &lhs,
    dynshifted_SequenceContainer const &rhs
  )
    {return StaticOffset == rhs.offset && lhs.cont == rhs.cont;}
  template<typename Container::difference_type StaticOffset>
  friend bool operator ==
  (
    dynshifted_SequenceContainer const &lhs,
    shifted_SequenceContainer<Container, StaticOffset> const &rhs
  )
    {return lhs.offset == StaticOffset && lhs.cont == rhs.cont;}
  friend bool operator != 
  (
    dynshifted_SequenceContainer const &lhs,
    dynshifted_SequenceContainer const &rhs
  )
    {return lhs.cont != rhs.cont;}
  template<typename Container::difference_type StaticOffset>
  friend bool operator !=
  (
    shifted_SequenceContainer<Container, StaticOffset> const &lhs,
    dynshifted_SequenceContainer const &rhs
  )
    {return StaticOffset != rhs.offset || lhs.cont != rhs.cont;}
  template<typename Container::difference_type StaticOffset>
  friend bool operator !=
  (
    dynshifted_SequenceContainer const &lhs,
    shifted_SequenceContainer<Container, StaticOffset> const &rhs
  )
    {return lhs.offset != StaticOffset || lhs.cont != rhs.cont;}
  friend bool operator < 
  (
    dynshifted_SequenceContainer const &lhs,
    dynshifted_SequenceContainer const &rhs
  )
    {return lhs.cont < rhs.cont;}
  template<typename Container::difference_type StaticOffset>
  friend bool operator <
  (
    shifted_SequenceContainer<Container, StaticOffset> const &lhs,
    dynshifted_SequenceContainer const &rhs
  )
    {return StaticOffset < rhs.offset || lhs.cont < rhs.cont;}
  template<typename Container::difference_type StaticOffset>
  friend bool operator <
  (
    dynshifted_SequenceContainer const &lhs,
    shifted_SequenceContainer<Container, StaticOffset> const &rhs
  )
    {return lhs.offset < StaticOffset || lhs.cont < rhs.cont;}
  friend bool operator <= 
  (
    dynshifted_SequenceContainer const &lhs,
    dynshifted_SequenceContainer const &rhs
  )
    {return lhs.cont <= rhs.cont;}
  template<typename Container::difference_type StaticOffset>
  friend bool operator <=
  (
    shifted_SequenceContainer<Container, StaticOffset> const &lhs,
    dynshifted_SequenceContainer const &rhs
  )
    {return StaticOffset <= rhs.offset || lhs.cont <= rhs.cont;}
  template<typename Container::difference_type StaticOffset>
  friend bool operator <=
  (
    dynshifted_SequenceContainer const &lhs,
    shifted_SequenceContainer<Container, StaticOffset> const &rhs
  )
    {return lhs.offset <= StaticOffset || lhs.cont <= rhs.cont;}
  friend bool operator > 
  (
    dynshifted_SequenceContainer const &lhs,
    dynshifted_SequenceContainer const &rhs
  )
    {return lhs.cont > rhs.cont;}
  template<typename Container::difference_type StaticOffset>
  friend bool operator >
  (
    shifted_SequenceContainer<Container, StaticOffset> const &lhs,
    dynshifted_SequenceContainer const &rhs
  )
    {return StaticOffset > rhs.offset || lhs.cont > rhs.cont;}
  template<typename Container::difference_type StaticOffset>
  friend bool operator >
  (
    dynshifted_SequenceContainer const &lhs,
    shifted_SequenceContainer<Container, StaticOffset> const &rhs
  )
    {return lhs.offset > StaticOffset || lhs.cont > rhs.cont;}
  friend bool operator >= 
  (
    dynshifted_SequenceContainer const &lhs,
    dynshifted_SequenceContainer const &rhs
  )
    {return lhs.cont >= rhs.cont;}
  template<typename Container::difference_type StaticOffset>
  friend bool operator >=
  (
    shifted_SequenceContainer<Container, StaticOffset> const &lhs,
    dynshifted_SequenceContainer const &rhs
  )
    {return StaticOffset >= rhs.offset || lhs.cont >= rhs.cont;}
  template<typename Container::difference_type StaticOffset>
  friend bool operator >=
  (
    dynshifted_SequenceContainer const &lhs,
    shifted_SequenceContainer<Container, StaticOffset> const &rhs
  )
    {return lhs.offset >= StaticOffset || lhs.cont >= rhs.cont;}


  constexpr size_type size() const {return cont.size();}
  constexpr size_type max_size() const {return cont.max_size();}
  void resize(size_type n) {return cont.resize(n);}
  void resize(size_type n, value_type const &val) {return cont.resize(n, val);}
  constexpr bool empty() const {return cont.empty();} 

  template<class ...Args> iterator emplace(const_iterator pos, Args &&...args)
    {return cont.emplace(pos, std::move(args...));}
  template<class ...Args> void emplace_front(Args &&...args)
    {return cont.emplace_front(std::move(args...));}
  template<class ...Args> void emplace_back(Args &&...args)
    {return cont.emplace_back(std::move(args...));}
  iterator insert(const_iterator pos, value_type const &val)
    {return cont.insert(pos, val);}
  iterator insert(const_iterator pos, value_type &&val)
    {return cont.insert(pos, std::move(val));}
  iterator insert(const_iterator pos, size_type n, value_type const &val)
    {return cont.insert(pos, n, val);}
  template<class Iterator> void insert(iterator pos, Iterator it, Iterator jt)
    {return cont.insert(pos, it, jt);}
  iterator insert(const_iterator pos, std::initializer_list<value_type> init)
    {return cont.insert(pos, init);}
  void push_front(value_type const &val) {return cont.push_front(val);}
  void push_front(value_type &&val) {return cont.push_front(std::move(val));}
  void push_back(value_type const &val) {return cont.push_back(val);}
  void push_back(value_type &&val) {return cont.push_back(std::move(val));}

  void clear() {return cont.clear();}
  iterator erase(const_iterator pos) {return cont.erase(pos);}
  iterator erase(const_iterator it, const_iterator jt)
    {return cont.erase(it, jt);}
  void pop_front() {return cont.pop_front();}
  void pop_back() {return cont.pop_back();}

  iterator begin() {return cont.begin();}
  constexpr const_iterator begin() const {return cont.begin();}  
  constexpr const_iterator cbegin() const {return cont.cbegin();}
  iterator end() {return cont.end();}
  constexpr const_iterator end() const {return cont.end();}
  constexpr const_iterator cend() const {return cont.cend();}
  reverse_iterator rbegin() {return cont.rbegin();}
  constexpr const_reverse_iterator rbegin() const {return cont.rbegin();}
  constexpr const_reverse_iterator crbegin() const {return cont.crbegin();}
  reverse_iterator rend() {return cont.rend();}
  constexpr const_reverse_iterator rend() const {return cont.rend();}
  constexpr const_reverse_iterator crend() const {return cont.crend();}
  reference front() {return cont.front();}
  constexpr const_reference front() const {return cont.front();}
  reference back() {return cont.back();}
  constexpr const_reference back() const {return cont.back();}
  reference operator[] (difference_type pos)
    {return cont.operator[](pos-offset);}
  constexpr const_reference operator[] (difference_type pos) const
    {return cont.operator[](pos-offset);}
  reference at (difference_type pos)
    {if(pos-offset<0) throw std::out_of_range(""); return cont.at(pos-offset);}
  constexpr const_reference at (difference_type pos) const
    {if(pos-offset<0) throw std::out_of_range(""); return cont.at(pos-offset);}
  iterator find(difference_type pos)
    {return cont.begin()+(pos-offset);}
  constexpr const_iterator find(difference_type pos) const
    {return cont.cbegin()+(pos-offset);}
};

template<class T, std::size_t N>
using dynshifted_array = dynshifted_SequenceContainer<std::array<T, N>>;

template<class T>
using dynshifted_vector = dynshifted_SequenceContainer<std::vector<T>>;

template<class T>
using dynshifted_deque = dynshifted_SequenceContainer<std::deque<T>>;

#endif

I’m doing this hobbystically, and I’m quite much of a greenhorn with programming, so I’d highly appreciate any comments. Thanks in advance!

\$\endgroup\$
4
\$\begingroup\$

I believe that you are expending way too much energy trying to solve something that should be a non-problem. Simply always let your containers be zero based, if you have for example 1-based indexes as input, simply subtract 1 from them as soon as you get the input and convert back right before output. Always use zero-based indexes internally and only convert as close to input/output as possible.

(too large for comment really)

\$\endgroup\$
  • \$\begingroup\$ If this was for a one-time use, then yes, I agree: this would be an extreme overkill. But, it’s a one-time write. I expend so much energy to write this this time – and I have a more convenient container for the rest of my life. Is it such a bad idea? \$\endgroup\$ – gaazkam Nov 18 '16 at 13:34
  • \$\begingroup\$ Plus, this (alongside with asInt) is just one of quite a lot ideas I have to include in a purely hobbystically written and completely non-production “library” of wrappers and data structures to ease solving uva.onlinejudge.org tasks… The idea comes from the fact how I noticed much of my code in these tasks was repetitive and not very neat… so I thought I’d write a bunch of helpers to neaten these codes \$\endgroup\$ – gaazkam Nov 18 '16 at 13:38
  • 1
    \$\begingroup\$ You are of course free to do as you please, but in my 10+ years of solving online judge type problems and in my life as a professional software engineer, I have never had use for such a container. In fact including such code would take more time than to adjust the values when I read them in. Because #include <whatever.hpp is simply more text than -1 once when I read in the value. \$\endgroup\$ – Emily L. Nov 19 '16 at 12:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.