I have a template class representing an array of numerical values.
I want this class to work for any type of numerical value (e.g. int, double, etc.) and three types of container (std::vector, std::deque, and std::list).
Here are the relevant bits of the implementation for my specific problem :
template < typename Numeric_t, typename Container = std::vector<Numeric_t> >
class Array {
// field member
Container m_data;
// other stuff here
// ...
// random element access for std::vector and std::deque
Numeric_t & operator[] (unsigned int index) { return m_data[index]; }
// random element access for std::list
Numeric_t & operator [] (unsigned int index) {
std::list<Numeric_t> :: iterator it = m_data.begin();
std::advance(it, index);
return *it;
}
}
Of course, the compiler doesn't allow me to overload the operator [].
What I would need is a kind of partial specialization for operator [] specific for std::list, but partial template function specialization is not allowed either in C++.
(I know that random element access is not efficient for a list, but that's not the point here).
Ideally, in the client code I would like to use the Array class like this :
Array < int, std::vector<int> > vec;
Array < int, std::list<int> > lst;
// fill arrays here
// ...
std::cout << vec[0] << std::endl;
std::cout << lst[0] << std::endl;
After lot of research I was not able to find a working solution.
What would be the most elegant way to solve this problem ?
Thanks for your help.
A clean solution is to use full-class template specialization. The different specializations can be derived form one common base class, in order to share common code.
Write a class ArrayBase containing all the code that does not depend on the particular container type and that grants access to the container, by making it protected or making Array a friend class.
template <class Numeric_t, class Container>
class Array
: public ArrayBase<Numeric_t, Container>
{
// Container specific code, generic version that works for all containers.
};
template <class Numeric_t>
class Array<Numeric_t, std::vector<Numeric_t>>
: public ArrayBase<Numeric_t, std::vector<Numeric_t>>
{
// Optimized code for std::vector.
}
Another approach: You can also write a static member function containing code to access the idx-th entry of the container and specialize that function:
template <class Numeric_t, class Container>
class Array
{
template <class Cont>
static Numeric_t get(Cont const& container, unsigned int idx)
{
std::list<Numeric_t>::iterator it = container.begin();
std::advance(it, idx);
return *it;
}
template <>
static Numeric_t get(std::vector<Numeric_t> const& container, unsigned int idx)
{
return container[idx];
}
public:
Numeric_t operator[](unsigned int idx) const { return get(m_data, idx); }
};
I am sorry, this does not work. I forgot that you can't specialize static member functions ... again.
Another alternative is to use SFINAE, but it is a non-idiomatic use of it and I would not recommend it in this case.
Related
If I have a class containing only std::vector of any type as data member and I would like to make a generic function allowing me to retrieve elements by index in any vector.
What can I do to create such a function. I tried to do it using pointers to my getters and it worked but I don't know if it is really a good solution.
Is there an example of such class
class S
{
private:
std::vector<int> someIntegers;
std::vector<double> someDoubles;
std::vector<double> someDoubles2;
std::vector<int> someIntergers2;
std::vector<B> someBs;
public:
const std::vector<int>& getSomeIntegers1() const { return someIntergers; }
// and so on ...
}
My solution is to do that:
template<typename T>
std::optional<T> getByIndex(const S& s, const std::vector<T>& (S::*getCnt)() const , size_t index = 0)
{
if (const auto& cnt = (s.*getCnt)();
index >= 0 && index < cnt.size())
return cnt.at(index);
return {};
}
I'm not sure if it's a great solution due to the lack of readability.
If you want to have a generic access that routes to individual members based on the template parameter, you must define the mapping manually. However, using the template argument as selector will not support cases with multiple member vectors of the same type, for example the someDoubles and someDoubles2.
Here is a sample code to retrieve the correct vector
template <class T>
std::vector<T>& getContainer();
template <>
std::vector<int>& getContainer() {
return someIntegers;
}
template <>
std::vector<double>& getContainer() {
return someDoubles;
}
// Do so for every type you want to support
guess I have a
class C1 : public B { /*...*/ };
class C2 : public B { /*...*/ };
std::map<std::string, C1> myMap;
std::vector<C2> myVector;
Is there a way (and what would be the syntax) to call a function foo that…
just needs to process the functionalities of B
just needs to process them on all elements of map and vector without caring how they are organized?
std::vector and std::map are both std::_Container_base's but i have no clue how to write the syntax for (pseudocode):
void foo(std::_Container_base-of-Bs)
EDIT: it's _Container_base, not _Tee
The C++ way is to use templates and iterators.
template <typename ForwardIterator>
void process_bs(ForwardIterator first, ForwardIterator last) {
std::for_each(first, last, [](B& b) {
// do something to b here
});
}
For vector, list, deque and set, you can trivially call this using begin and end:
process_bs(v.begin(), v.end());
For map, the element type is pair<const Key, Value>, so you have to adapt the iterators. You can use this with Boost.Range, for example:
#include <boost/range/adaptor/map.hpp>
auto values = m | boost::adaptors::map_values;
process_bs(values.begin(), values.end());
EDIT: The below is a survey on the workarounds, whereas the actual question is not answered therein. So here is the answer: I don't know whether one can process std::_Container_base without knowing if it is a map or a vector.
I couldn't find anything reasonable on the web regarding std::_Container_base, and particularly no C++ standard things, so I would guess it stems from a specific compiler implementation.
vector and map are completely different storage schemes. I suggest you to not use them generically in the same context. That is, from the first you could write a function template
template<typename T> foo(T&& t) { /* takes a vector and a map */ }
but at least when you access operator[], they'll behave differently. That would be unintuitive and error-prone.
However, this doesn't mean you cannot combine the two approaches -- and abstract on size(), operator[](int) and possibly other things like some insertion mechanism.
For example, in some recent code of mine, I have vector-storage scheme (which uses std::vector under the hood), as well as a piecewise constant vector (which uses a std::map). If you want to do this, you can derive those two from a common base class
template<typename T>
struct ContainerBase
{
virtual int size() const = 0;
virtual T operator[](int) const = 0;
virtual void insert(int, T) = 0; //if required
};
and then set up the required functionality in the derived classes Vector and Map.
template<typename T>
struct Vector
{
virtual T operator[](int i) const { return _v[i]; }
virtual T size() const { return _v.size(); }
// ... insert and so on
std::vector<T> _v;
};
template<typename T>
struct Map
{
virtual T operator[](int i) const
{
return *std::lower_bound(i); //add further checks if nothing is found
}
virtual T size() const { return _v.rbegin()->first; // return highest index }
// ... insert and so on
std::map<int, T> _v;
};
The Map implementation is just a sketch. You should choose some reasonable behaviour for it.
With this, it is easy to set up a function foo(ContainerBase&) which works for both Vector and Map.
To use transparently B subclasses into the foo function, you can do this way:
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <utility>
struct B{
int b_member;
};
class C1 : public B { /*...*/ };
class C2 : public B { /*...*/ };
std::map<std::string, C1> myMap;
std::vector<C2> myVector;
// all the magic is into get_B specializations
template<typename E, typename std::enable_if<std::is_base_of<B, E>::value>::type* a = nullptr>
B& get_B(E& elem)
{
return elem;
}
template<typename E, typename std::enable_if<std::is_base_of<B, typename E::second_type>::value>::type* a = nullptr>
B& get_B(E& elem)
{
return elem.second;
}
// foo can call get_B to hide implementation details of the container
template<typename T>
void foo( T& container)
{
for(auto& elem : container)
{
std::cout << get_B(elem).b_member << '\n';
}
}
int main()
{
myVector.resize(10);
myMap["one"] = {};
foo(myMap);
foo(myVector);
}
Thanks to SFINAE, foo uses the correct specialization of get_B to get a reference to the B subclass you want to process.
First of all, I have a template class that looks like this:
template <typename T>
class Configurable
{
public:
//protected:
T var_value;
std::string var_name;
std::string var_type;
Configurable()
: var_value(0), var_name("unnamed"), var_type("undefined")
{}
Configurable( T v_value, std::string v_name, std::string v_type )
: var_value(v_value), var_name(v_name), var_type(v_type)
{}
std::string get_name() {return var_name;}
};
I also have a container class named Config which has a couple of different Configurable lists for storage of Configurable ints, bools and floats. I want to overload the [] operator of Config so that it returns a Configurable with the given name (regardless of the type) from one of the lists, but this doesn't seem to work:
template <typename T>
Configurable<T>& operator[] ( const std::string v_name_arg );
The compiler returns an error of 'no match for operator[]'. So my question is - how can I make this work? Is it even possible to do it using templates or should I find a different approach with inheritance?
EDIT: Sorry for all the confusion. Here's the container class I'm talking about:
class Config
{
public:
//private:
std::list < Configurable<int> > list_int;
std::list < Configurable<float> > list_float;
std::list < Configurable<double> > list_double;
std::list < Configurable<bool> > list_bool;
//public:
Config(){}
template <typename T>
Configurable<T>& operator[] ( const std::string &v_name_arg );
};
The problem with declaring the templated operator[] without any argument that depends on the template parameter is that the compiler cannot determine the type T from a call in the form config["name"].
One solution, considering code readability, would be changing the operator[] to a method such as:
template <typename T>
Configurable<T>& get ( const std::string v_name_arg );
Then, the call should be written like:
config.get<int>("name")
Also, consider passing the string by reference (const std::string&) to avoid unnecessary copies of a std::string passed to the method/operator.
As described above, it's a syntax error.
WHen you write:
template <typename T>
Configurable<T>& operator[] ( const std::string v_name_arg );
You try to define a free standing operator[] as if it would be a free standing function.
But according to your explanations, operator[] should be a member of your container Config.
So the its definition should look somewhat like:
template <typename T>
class Config {
//...
public:
Configurable<T>& operator[] (const std::string v_name_arg) { /* return a ref to a Configurable */ };
};
With such a definition, the stuff compiles, and you can use it for example with :
int main()
{
Configurable<int> c;
Config<int> cfg;
auto a = cfg["test"];
}
I have a class Vector which represents a mathematical vector of a given template class. I want to be able to save the vectors in two different ways:
template <class T>
class Vector
{
private:
T* elements;
};
and
template <class T, unsigned int D>
class Vector
{
private:
T elements[D];
};
In the first example I allocate and free the array with new and delete in constructor and destructor.
Now since I don't want to write all the methods twice for both classes, and since it wouldn't even compile this way because I have two classes with the same name but different template arguments, I would like to combine both classes into one class like so:
template <class T, int D = -1>
class Vector
{
public:
Vector<T, D> add(const Vector<T, D>& add) const;
private:
T elements[D];
};
template <class T>
class Vector<T, -1>
{
public:
Vector<T, D> add(const Vector<T, D>& add) const;
private:
T* elements;
};
So the second part is just a partial template specialization of the first one. If no dimensions are given the dynamically allocated option should be used (default argument for D). As an example I added a function to calculate the sum of two vectors.
Now my problem is that I have to give two implementations for what is logically just one function. Whenever I access the elements array it's exactly the same syntax in the dynamic and in the static Vector class. Can I somehow combine both implementations into just one implementation of the add function (and likewise of all similar functions)?
If I cannot solve the problem this way, do you have other ideas of how to create the Vector class with both dynamic and static memory allocation?
I'd go for a policy-based design, similar to the way how std::vector handles allocation.
In your case it means:
Define a class which stores the vector elements but only provides a minimal interface. (Policy)
Define your vector interface independent of the way the elements are stored in the policy. It accesses the elements in a way independent of that implementation. The policy class should be added as a template type parameter (which can have a default value), so the user of your vector class can choose which policy to use. Inherit from the policy class or add a member of its type (privately if you don't want to expose the policy interface in the public interface).
Example (here with aggregation instead of inheritance):
// The policy default implementation:
template <class T, int D>
class VectorStorage
{
T elements[D];
public:
T& operator[](int x) {
return elements[x];
}
const T& operator[](int x) const {
return elements[x];
}
};
class VectorStorage<T, -1>
{
T* elements; // (for allocation, see below)
public:
T& operator[](int x) {
return elements[x];
}
const T& operator[](int x) const {
return elements[x];
}
};
// The vector implementation, independent of the storage,
// but defaulting to the one above:
template <class T, int D = -1, class Storage = VectorStorage<T,D>>
class Vector
{
Storage storage;
public:
Vector<T, D> add(const Vector<T, D>& add) const {
// Access your elements using "storage[x]"
}
};
Note that you need a suitable constructor for your policy class (as in the case of the dynamic storage type, you need the size during construction). Provide a unique constructor interface to all of your specializations, not only for the one which need it; and call the constructor in the vector's constructor appropriately:
// within class VectorStorage<T,-1>:
VectorStorage(int size) : elements(new T[size]) {}
~VectorStorage() { delete[] elements; }
// within class VectorStorage<T,D>:
VectorStorage(int /* ignored */) {}
// within class Vector:
Vector(int size) : storage(size) {}
Alternatively, to support client code like Vector<int,5> myVector; (i.e. default constructor on the static size version), provide a default constructor which is only allowed to be called for the static size version:
Vector() : storage(D) {
static_assert(D != -1, "The default constructor is only allowed for the static-sized version of Vector.");
}
Now a user can even use Vector with std::vector as the storage back-end: Vector<int, -1, std::vector<int>> or Vector<int, 5, std::vector<int>>. Or even Vector<int, 5, std::array<int,5>>.
I would do something like the following, i.e specialize only the data part:
template <class T, int D = -1>
class VectorData
{
public:
int size() const { return D; }
protected:
T elements[D];
};
template <class T>
class VectorData<T, -1>
{
public:
explicit VectorData(int size) : elements(size) {}
int size() const { return elements.size(); }
protected:
std::vector<T> elements;
};
template <class T, int D = -1>
class Vector : protected VectorData<T, D>
{
public:
using VectorData<T, D>::VectorData;
Vector add(const Vector& add) const
{
Vector res(*this);
for (int i = 0; i != this->size(); ++i) {
res.elements[i] += add.elements[i];
}
return res;
}
};
I'm implementing four algorithms that are completely identical except for what data structure they use — two use priority_queue, one uses stack, and the last uses queue. They're relatively long, so I'd like to have just one function template that accepts the container type as a template argument and then have each algorithm call that template with the appropriate argument, like so:
template <class Container>
void foo(/* args */)
{
Container dataStructure;
// Algorithm goes here
}
void queueBased(/* args */)
{
foo<queue<Item> >(/* args */);
}
void stackBased(/* args */)
{
foo<stack<Item> >(/* args */);
}
I've managed to do just this with the priority_queue- and stack-based implementations, but I can't do the same for the queue-based algorithm because it uses a different name to access the foremost element (front( ) instead of top( )). I know that I could specialize the template for this case, but then I'd have a big stretch of duplicated code (which is what I'm trying to avoid).
What's the best way to accomplish this? My first instinct was to create a wrapper class for queue that adds a top( ) operation equivalent to stack's, but I've been reading that subclassing STL classes is a no-no. How should I get this behavior, then?
You can write a non-member top function overloaded on the type of the container adapter:
template <typename T>
T& top(std::stack<T>& s) { return s.top(); }
template <typename T>
T& top(std::queue<T>& q) { return q.front(); }
// etc.
If you actually use a different sequence container with the container adapters (via their Sequence template parameter), you'll need to modify the overloads appropriately to handle that.
It might just be more straightforward to use a sequence container (e.g. std::vector) directly rather than using one of the sequence adapters.
You can use partial specialization to select the right method:
template<class Container>
struct foo_detail {
static typename Container::value_type& top(Container &c) { return c.top(); }
static typename Container::value_type const& top(Container const &c) { return c.top(); }
};
template<class T, class Underlying>
struct foo_detail<std::queue<T, Underlying> > {
typedef std::queue<T, Underlying> Container;
static typename Container::value_type& top(Container &c) { return c.front(); }
static typename Container::value_type const& top(Container const &c) { return c.front(); }
};
template<class Container>
void foo(/* args */)
{
Container dataStructure;
// Use foo_detail<Container>::top(dataStructure) instead of dataStructure.top().
// Yes, I know it's ugly. :(
}
You can create a wrapper around std::queue without using inheritance; in fact, inheritance would be the wrong tool here because you're trying to decorate a queue rather than refining or extending the queue. Here's one possible implementation:
template <typename QueueType>
class QueueWrapper {
public:
explicit QueueWrapper(const QueueType& q) : queue(q) {
// Handled in initializer list
}
typedef typename QueueType::value_type value_type;
value_type& top() {
return queue.front();
}
const value_type& top() const {
return queue.front();
}
void pop() {
queue.pop();
}
private:
QueueType queue;
};
Hope this helps!
queue, priority_queue and stack are all container adaptors; they are wrappers around an underlying container (by default, deque for queue and stack and vector for priority_queue).
Since vector, deque and list (the "real" container classes) share most of their methods, you could cut the middle man and use those classes instead.
And keep in mind that public inheritance is not a good idea for STL containers; private inheritance is okay (and probably what you want).
front() and top() are specific to certain types of containers, but all STL containers support *begin().