title: Sets (arrays of heterogeneous types) in C++
body: <p>I would like to simulate python sets in C++.
  According to the <a href="https://isocpp.org/wiki/faq/containers#heterogeneous-containers" rel="nofollow noreferrer">faq</a>, an idiomatic way to do this would be to use an <code>std::vector</code> which stores pointers (better if smart pointers) to a handle class which is then overloaded by the specific types which we would like to store in the simulated set.</p>
  
  <p>This is my attempt:</p>
  
  <pre class="lang-cpp prettyprint-override"><code>// experimenting with vectors of heterogeneous elements (like sets in python)
  #include &lt;iostream&gt;
  #include &lt;memory&gt;
  #include &lt;string&gt;
  #include &lt;vector&gt;
  
  
  // Handle can wrap an int, a double, or a string.
  class Handle {
  public:
    Handle();
    virtual int val();
    virtual double val();
    virtual std::string val();
  };
  
  
  class Int : public Handle {
  public:
    Int(const int n) : value(n) {};
    int val() override { return value; };
  private:
    int value;
  };
  
  
  class Double : public Handle {
  public:
    Double(const double n) : value(n) {};
    double val() override { return value; };
  private:
    double value;
  };
  
  
  class String : public Handle {
  public:
    String(const std::string&amp; n) : value(n) {};
    std::string val() override { return value; };
  private:
    std::string value;
  };
  
  
  int main() {
    // v simulates a set with 12 elements of types int, double, or string.
    std::vector&lt;std::shared_ptr&lt;Handle&gt;&gt; v(12);
  
    for (int i = 0; i &lt; v.size(); i += 3) {
      v[i] = std::shared_ptr&lt;Int&gt;(new Int(i));
      v[i + 1] = std::shared_ptr&lt;Double&gt;(new Double(i + 1.));
      v[i + 2] = std::shared_ptr&lt;String&gt;(new String(std::to_string(i + 2)));
    }
  
    for (auto&amp; it : v) {
      std::cout &lt;&lt; it-&gt;val() &lt;&lt; std::endl;
    }
  }
  </code></pre>
  
  <p>This approach would be preferable to declaring <code>v</code> as an <code>std::vector&lt;Handle*&gt;</code>, because using smart pointers would allow me to forget about deleting manually the pointers, while at the same time achieving runtime polymorphism.</p>
  
  <p>The code above however does not compile, because we are not allowed to overload a function (<code>val()</code> in this case) only on the return types.</p>
  
  <p>Is there a way to fix my code so that I can simulate a set with different types? Is there a better, idiomatic way to do it?</p>
  
  <h1>Edit</h1>
  
  <p>Here's how I changed my code after n. 'pronouns' m.'s answer.
  The code seems to work, and I am happy with it as an exercise in using inheritance and smart pointers (even though it's not the best solution for the specific problem at hand, see Maxim Egorushkin's answer for a much better approach).</p>
  
  <pre class="lang-cpp prettyprint-override"><code>// experimenting with vectors of heterogeneous elements (like sets in python)
  #include &lt;iostream&gt;
  #include &lt;memory&gt;
  #include &lt;string&gt;
  #include &lt;vector&gt;
  
  
  // Handle can wrap an int, a double, or a string.
  class Handle {
  public:
    Handle() {};
    virtual void print(std::ostream&amp;) = 0;
  };
  
  
  class Int : public Handle {
  public:
    Int(const int n) : value(n) {};
    void print(std::ostream&amp; s) override { s &lt;&lt; value &lt;&lt; std::endl; };
  private:
    int value;
  };
  
  
  class Double : public Handle {
  public:
    Double(const double n) : value(n) {};
    void print(std::ostream&amp; s) override { s &lt;&lt; value &lt;&lt; std::endl; };
  private:
    double value;
  };
  
  
  class String : public Handle {
  public:
    String(const std::string&amp; n) : value(n) {};
    void print(std::ostream&amp; s) override { s &lt;&lt; value &lt;&lt; std::endl; };
  private:
    std::string value;
  };
  
  
  int main() {
    std::vector&lt;std::shared_ptr&lt;Handle&gt;&gt; v(12);
  
    for (size_t i = 0; i &lt; v.size(); i += 3) {
      v[i] = std::shared_ptr&lt;Int&gt;(new Int(i));
      v[i + 1] = std::shared_ptr&lt;Double&gt;(new Double(i + 1.));
      v[i + 2] = std::shared_ptr&lt;String&gt;(new String(std::to_string(i + 2)));
    }
  
    for (const auto&amp; it : v) {
      it-&gt;print(std::cout);
    }
  }
  </code></pre>