Note that there are some explanatory texts on larger screens.

plurals
  1. POImplementing a map_keys_iterator by derivation: a single compiler error
    text
    copied!<p>I was working again with C++ during the weekend and came to notice something that I'm not sure where does it come from.</p> <p><a href="https://stackoverflow.com/questions/1443793/iterate-keys-in-a-c-map">Following the advice in this thread</a>, I decided to implement a <code>map_keys_iterator</code> and <code>map_values_iterator</code>. I took the -- I think -- recommended-against approach of deriving a class from <code>std::map&lt;K,V&gt;::iterator</code> and implementing it as such:</p> <pre><code>template &lt;typename K, typename V&gt; struct map_values_iterator: public std::map&lt;K,V&gt;::iterator { // explicitly call base's constructor typedef typename std::map&lt;K,V&gt;::iterator mIterator; map_values_iterator (const mIterator&amp; mi) : mIterator(mi) {}; const V&amp; operator* () const { return (*this)-&gt;second; } }; </code></pre> <p>So far, so good, and the following code works (nvm the Unicode, I default to work with i18n-capable terminals):</p> <pre><code>typedef std::map&lt;double,string&gt; Map; Map constants; constants[M_PI] = "π"; constants[(1+sqrt(5))/2] = "φ"; constants[exp(M_PI)-M_PI] = "fake_20"; // ... fill map with more constants! map_values_iterator&lt;double, std::string&gt; vs(constants.begin()); for (; vs != m.end(); ++vs) { cout&lt;&lt; (vs != m.begin() ? ", " : "")&lt;&lt; *vs; } cout&lt;&lt; endl; </code></pre> <p>This code prints the expected result, something like (because a Map's elements are ordered):</p> <pre><code>..., φ, ..., π, ...., fake_20, .... </code></pre> <p>So I'd guess a <code>map_keys_iterator</code> would work in a similar way as well. I took the care that a Map's value_type is actually <code>pair&lt;const K, V&gt;</code> so the <em>keys</em> version will return a value.</p> <p>However, it is unwieldly to have to declare the iterator's type so I wanted to create a caller with the classical <code>make_pair</code>-like idiom. And this is where trouble begins:</p> <pre><code>template &lt;typename K, typename V&gt; map_values_iterator&lt;K,V&gt; map_values(const typename std::map&lt;K,V&gt;::iterator &amp;i) { return lpp::map_values_iterator&lt;K,V&gt; (i); } template &lt;typename K, typename V&gt; map_values_iterator&lt;K,V&gt; map_values(const typename std::map&lt;K,V&gt;::const_iterator &amp;i) { return lpp::map_values_iterator&lt;K,V&gt; (i); } </code></pre> <p>I'm relatively sure this function has the right signature and constructor invocation. However if I attempt to call the function from code:</p> <pre><code>auto vs= map_values(constants.begin()); </code></pre> <p>I get a single STL compiler error of the form:</p> <pre><code>error: no matching function for call to ‘map_values(std::_Rb_tree_iterator&lt;std::pair&lt;const double, std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt; &gt; &gt;)’ </code></pre> <p>I'm assuming here that in this particular case the whole <code>_Rb_tree_iterator</code> is actually the correct iterator for which <code>map::iterator</code> is typedefed; I'm not completely sure however. I've tried to provide more overloads to see if one of them matches (drop the reference, drop the const, use only non-const_iterator variants, etc) but so far nothing allows the signature I'm interested in.</p> <p>If I store the base iterator in a variable before calling the function (as in <code>auto begin= constans.begin(); auto vs= map_values(begin);</code>) I get the exact same base error, only the description of the unmatched call is obviously different (in that it is a "const blah&amp;").</p> <p>My first attempt at implementing this sort of iterator was by creating a base class that aggregated <code>map::iterator</code> instead of inheriting, and deriving two classes, each with the adequate <code>operator*</code>, but that version ran into many more problems than the above and still forced me to replicate too much of the interface. So I tried this option for code-expedition.</p> <p>I've tried to look for answers to this issue but my Google-fu isn't very strong today. Maybe I am missing something obvious, maybe I forgot something with the derivation (although I'm almost sure I didn't -- iterators are unlike containers), maybe I am actually required to specify all the template parameters for the map, or maybe my compiler is broken, but whatever it is I can't find it and I am having real trouble understanding what is the <em>actual</em> thing the compiler is complaining about here. In my previous experience, if you are doing something wrong with the STL you are supposed to see a diarrhoea of errors, not only <strong>one</strong> (which isn't STL to boot).</p> <p>So... any (well-encapsulated) pointers would be appreciated.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload