I'm trying to write a simple generalised function for iteration over container elements. Every element is converted to std::string
(no matter how) and stored in another place. The basic version was trivial:
template<class Container>
void ContainerWork(const Container& c)
{
for(const auto& elem : c) {
/* convert to string and store*/
}
}
Then it became necessary to add specialisation for containers with value type std::string
and code transformed to:
template<typename T, template<typename, typename> class Container, class Allocator>
void ContainerWork(Container<T, Allocator> c)
{
for(const T& elem : c) {
/* convert to string and store*/
}
}
template<template<typename, typename> class Container, class Allocator>
void ContainerWork(Container<std::string, Allocator> c)
{
for(const std::string& elem : c) {
/* frame elem in quotes*/
}
}
It works great, but now I can use only sequenced containers (vector
, list
, etc.), but I want also use set
and and unordered_set
. Any ideas how do this without "copy-paste" realisation for container with 4 params? I am trying to play with decltype(Container)::value_type
but with no luck.
I may use most of c++11 features (compiler - VS2012 or GCC 4.8.x)
The Standard Template Library (STL) is a set of C++ template classes to provide common programming data structures and functions such as lists, stacks, arrays, etc. It is a library of container classes, algorithms, and iterators. It is a generalized library and so, its components are parameterized.
The Standard Template Library, or STL, is a C++ library of container classes, algorithms, and iterators; it provides many of the basic algorithms and data structures of computer science. The STL is a generic library, meaning that its components are heavily parameterized: almost every component in the STL is a template.
STL has three key components - containers (popular templatized data structures), iterators and algorithms.
In C++, there are generally 3 kinds of STL containers: Sequential Containers. Associative Containers. Unordered Associative Containers.
That's why all of the standard library's algorithms work on iterators rather than containers.
You can change your core function to work on iterators rather than containers. This will require partial specialisation, which doesn't exist for function templates, so we'll use the delegate-to-class trick:
template <typename It>
void DoIteratorWork(It start, It end)
{
DoIteratorWork_Impl<It, typename std::iterator_traits<It>::value_type>::call(start, end);
}
template <typename It, typename ValueType>
struct DoIteratorWork_Impl
{
static void call(It start, It end)
{
for (; start != end; ++start) {
// operate on *it
}
}
};
template <typename It>
struct DoIteratorWork_Impl<It, std::string>
{
static void call(It start, It end)
{
for (; start != end; ++start) {
// operate on *it
}
}
};
If you really want to, you can then create a wrapper around this:
template <class Container>
void DoContainerWork(const Container& c)
{
using std::begin; using std::end; // enable ADL of begin and end
return DoIteratorWork(begin(c), end(c));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With