Context-sensitive container / array access interface C ++

Is there possibly an extended serial element access semantics that works in containers? sort of:

element_of(std_pair).get<1>(); element_of(boost_tuple).get<0>(); element_of(pod_array).get<2>(); 

in principle, I can write myself, but I would prefer not to reinvent the wheel. thanks

+4
source share
3 answers

I do not know about that.

Most likely, you can simply implement the free receipt function for the types you are interested in. Boost.Tuple already has this. std::pair has it in C ++ 0x. And the rest should not be too complicated.

eg

 #include <iostream> #include <utility> #include <vector> #include <boost/tuple/tuple.hpp> namespace getter { template <size_t Index, class Container> typename Container::reference get(Container& c) { return c[Index]; } template <size_t Index, class Container> typename Container::const_reference get(const Container& c) { return c[Index]; } template <size_t Index, class T> T& get(T *arr) { return arr[Index]; } namespace detail { template <size_t Index, class T, class U> struct PairTypeByIndex; template <class T, class U> struct PairTypeByIndex<0u, T, U> { typedef T type; type& operator()(std::pair<T, U>& p) const { return p.first; } const type& operator()(const std::pair<T, U>& p) const { return p.first; } }; template <class T, class U> struct PairTypeByIndex<1u, T, U> { typedef U type; type& operator()(std::pair<T, U>& p) const { return p.second; } const type& operator()(const std::pair<T, U>& p) const { return p.second; } }; } template <size_t Index, class T, class U> typename detail::PairTypeByIndex<Index, T, U>::type& get(std::pair<T, U>& p) { return detail::PairTypeByIndex<Index, T, U>()(p); } template <size_t Index, class T, class U> const typename detail::PairTypeByIndex<Index, T, U>::type& get(const std::pair<T, U>& p) { return detail::PairTypeByIndex<Index, T, U>()(p); } using boost::get; } int main() { boost::tuple<int, int> tuple(2, 3); std::cout << getter::get<0>(tuple) << '\n'; std::vector<int> vec(10, 1); vec[2] = 100; std::cout << getter::get<2>(vec) << '\n'; const int arr[] = {1, 2, 3, 4, 5}; std::cout << getter::get<4>(arr) << '\n'; std::pair<int, float> pair(41, 3.14); ++getter::get<0>(pair); const std::pair<int, float> pair_ref = pair; std::cout << getter::get<0>(pair_ref) << ' ' << getter::get<1>(pair_ref) << '\n'; } 
+1
source

Containers have different ways of accessing them, since they are fundamentally different. The closest thing you get in STL is iterators. All standard containers have iterators, so you can iterate over them and use the same algorithms with them using these iterators. However, what each iterator contains differs depending on the container (should only have an element, but maps have pairs). And if you look at a couple in the form of a container, it will not fit into the rest, because it does not have iterators.

In most cases, using iterators solves the problem. However, obviously, this does not completely solve the problem, and STL does not have a solution for it. Boost may, but I do not know about it.

The main thing, however, is that containers are inherently different from each other and to a large extent cannot be interchangeable. Using standard iterators, most containers can be easily interchanged. But usually it makes no sense to change one container to another without changing some code around it, because they act differently. I believe that Scott Meyers emphasizes this in his book Effective STL.

If you are really trying to make the various containers interchangeable, I would suggest rethinking this and taking a closer look at what you are doing. This is most likely not a good idea. Now this may be a good idea for your specific application - of course I can’t say without knowing anything about it, and you would be the best judge of it, but in general, creating containers is a really interchangeable bad idea. Iterators allow you to reuse a lot of algorithms on them, but even there the type of algorithms that can be used in a particular container depends on the type of iterators that this container uses (random access, bidirectional, etc.).

So, no, I don’t know about the previously existing solution for accessing container elements other than iterators, but, generally speaking, I would advise against trying to use it. Containers are not interchangeable and are not intended.

+2
source

I do not know of any universal accessories that will work in all well-known container definitions in C ++. However, Boost.Range can be used as such to some extent.

For more flexibility, you probably need to implement it yourself. Maybe something to scratch:

 struct container_accessor { ... } template <typename Container> container_accessor make_accessor(Container& c) { ... } template <typename Container> container_const_accessor make_accessor(Container const& c) { ... } 

where and then specialize container_accessor for all necessary containers.

+1
source

Source: https://habr.com/ru/post/1299203/


All Articles