0

The standard library neglects to implement basic operations for std::set and std::map like

set<T> set<T>::getUnion(set<T> other)

and

bool map<K,V>::contains(K key)

I know there are verbose and/or indirect workarounds for these methods but if I want my code to be maximally readable and expressive, I'm going to have to inherit from the STL, write my own Set and Map classes, and implement them myself. And yes, I'm aware of the sermonizing against doing this but the fact is the STL is incomplete.

I've done this but now I can't initialize my new classes using, e.g.,

Set<int> s = {1,2,3,4};

How do I inherit these initializers from the std classes?

Chris Redford
  • 16,982
  • 21
  • 89
  • 109
  • `bool map::contains(K key)` is useful only in very narrow use cases. Most of the time, you want to access the value given a key. – R Sahu May 03 '14 at 00:23
  • So is `vector::back()`. Most of the time you just want to `push_back`, iterate, or access by index. But that didn't stop the STL authors from specifying `back`. The reality is, any operation implemented for a Python `dict` should be implemented for `map`. The same goes for Python `set`. The question isn't frequency of use but the expected mathematical, intuitive, and logical structure for what the data structure represents. – Chris Redford May 03 '14 at 14:18

2 Answers2

3

Despite the fact that publically inheriting from standard library containers is considered to be a bad idea, you can "inherit" the constructors:

template <typename T>
struct Set : std::set<T>
{
  using std::set<T>::set; // "inherit" the constructors.
};

then

Set<int> s{1,6,4,3,3,9};

Note that a better approach might be to implement functions:

template <typename C>
bool contains(const C& container, const typename C::key_type& key)
{
  return container.count(key);
}

and similarly for the union of sets.

Community
  • 1
  • 1
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • 1
    Why not make `contains` generic for 8 containers: `template bool contains(const C& c,const typename C::key_type& k) { return c.count(k); }`? – Daniel Frey May 02 '14 at 22:04
  • Inheriting from standard containers is discouraged because of the potential for slicing or improper destruction, which won't be a problem if you don't have any added data members or virtual functions and your derived destructor is default. Of course that means you're hoping the maintainer who comes after you knows those rules too. – Mark Ransom May 02 '14 at 23:08
  • @MarkRansom Agreed, but it won't be a problem as long as you don't try to `delete` via a base class pointer. But private inheritance seems reasonably safe to me. – juanchopanza May 02 '14 at 23:11
  • I get `error: ‘std::set::set’ names constructor` when I add `using std::set::set;`. – Chris Redford May 02 '14 at 23:13
  • @ChrisRedford You need C++11 support for that. See [this demo](http://ideone.com/pJK9bp). Without C++11, you have to do it by hand. – juanchopanza May 02 '14 at 23:15
  • I'm using C++11: `g++ -std=c++11 -O3 -g -Wall -DTRUE=1 -DFALSE=0 -DNULL=0 -g main.cpp` – Chris Redford May 02 '14 at 23:17
  • @ChrisRedford It could be that your version of gcc is not recent enough. I just tried it with gcc 4.8.2. – juanchopanza May 02 '14 at 23:20
1

For gcc 4.7.x, you have to call the initializer_list constructor for the set or map:

template <typename T>
class Set : public set<T> {
public:
    Set(){
        set<T>::set();
    }
    Set(initializer_list<T> iList) {
        set<T>::set(iList);
    }
};

Allowing

Set<int> s = {1,2,3,4};

But after much trial and error, I can't find a way to do this for std::map.

Also, it disables all the other constructors, requiring me to reimplement them, a task I'm not up to yet, so I'm just giving up on initializer lists for now. Anyone is welcome to submit an answer that reimplements all the constructors as Set and I'll choose it as the answer.

Chris Redford
  • 16,982
  • 21
  • 89
  • 109
  • You should probably add your very specific requirements to the question. Basically, you need something that supports C++11 minus inherited constructors. – juanchopanza May 03 '14 at 10:53
  • Yeah, it is looking like just using gcc 4.8 would solve these problems. Then I could use your answer, which I have verified works on a different machine with an updated compiler. – Chris Redford May 03 '14 at 14:03