1
\$\begingroup\$

I'd offer a couple of iterator accesses to the class member, both constant and non-constant. I came to the following solution, but it seems to me far more verbose than needed. I'd like somehow to merge the two function members get_c, get_m in some fashion, but I'm not sure if possible.

#include <iostream>
#include <vector>
#include <cstdint>

using my_t = uint64_t;

// Own implementation of 3D-vector. size() == m_X * m_Y * m_Z
class Package
{
    // 3D-strides
    const size_t m_X = 10, m_Y = 2, m_Z = 4;

public:

    std::vector<my_t> m_v;

    template <class I>
    typename std::enable_if<std::is_same<I, typename std::vector<typename std::iterator_traits<I>::value_type>::iterator>::value, std::vector<my_t>::iterator>::type
    get_it(I i, size_t x, size_t y, size_t z)
    {
        return std::next(i, x * m_X * m_Y + y * m_Z + z);
    }

    template <class I>
    typename std::enable_if<std::is_same<I, typename std::vector<typename std::iterator_traits<I>::value_type>::const_iterator>::value, std::vector<my_t>::const_iterator>::type 
    get_it(I i, size_t x, size_t y, size_t z) const
    {
        return std::next(i, x * m_X * m_Y + y * m_Z + z);
    }

    std::vector<my_t>::iterator
    get_m(size_t x, size_t y, size_t z)
    {
        return get_it(m_v.begin(), x, y, z);
    }

    std::vector<my_t>::const_iterator
    get_c(size_t x, size_t y, size_t z) const
    {
        return get_it(m_v.cbegin(), x, y, z);
    }

    Package() : m_v(m_X * m_Y * m_Z, 1)
    {}
};


void f_const(const Package & pkg)
{
    auto it = pkg.get_c(0, 1, 2);
    std::cout << "const: " << *it << "\n";
}

void f_modif(Package & pkg)
{
    auto it = pkg.get_m(0, 1, 2);
    *it += 10;
    std::cout << "modif: " << *it << "\n";
}

int main(int argc, char**argv)
{
    Package p;
    f_const(p);
    f_modif(p);
}

In other words, I'd like some context-aware single method for access. A two-methods functionally-equivalent solution could be

my_t & operator () (size_t x, size_t y, size_t z) {
  return *(m_v.begin() + x * m_X * m_Y + y * m_Z + z);
}

my_t operator () (size_t x, size_t y, size_t z) const {
  return *(m_v.cbegin() + x * m_X * m_Y + y * m_Z + z);
}

No surprise I'm still a novice in metaprogramming, but I'm wondering if this approach has some intrinstic fallacy.

\$\endgroup\$
4
  • 3
    \$\begingroup\$ Could you explain a bit more about what you're trying to do here? It looks like there's no need for the enable_if stuff at all. Why not just go with the usual C++ approach of having a const function called get returning a const_iterator, and non-const function also called get returning a plain iterator? \$\endgroup\$
    – user673679
    Oct 1 '19 at 10:58
  • \$\begingroup\$ I exactly need something akin, but perhaps, as suggested, over-complicated the boilerplate code. \$\endgroup\$ Oct 1 '19 at 11:20
  • \$\begingroup\$ What's the goal of the code? What problem should it solve? \$\endgroup\$
    – Mast
    Oct 1 '19 at 12:58
  • \$\begingroup\$ Code should offer two detailed accesses to 3D data (flattened in a vector), where arguments are a triple of coordinates. I'd enforce constness template selection inside functions not allowed to modify their Package argument \$\endgroup\$ Oct 1 '19 at 13:13