0

I was trying to return an iterator to a vector from a template function (not yet a template class member--I'm still writing that). The compiler kept giving me errors (copied below to to facilitate Google searches). I knew basically what the problem was, but the exact syntax was elusive.

I read the internet, searched SO, including Where and why do I have to put the "template" and "typename" keywords?, but didn't find an answer that worked. I figured I should ask the question and answer it myself here.

(Abbreviated) original code follows:

#include <vector>
#include <algorithm>  // std::lower_bound

template<typename T> std::vector<T>::iterator
              insertIntoVector(std::vector<T>& vec, const T& val)
{  itr = [some std::vector<T> iterator];
   return itr;  // return iterator to val in vec.
} // End of insertIntoVector();

Compiler errors:

error C2145: syntax error: missing ';' before identifier 'insertIntoVector'
error C2065: 'T' : undeclared identifier
error C2923: 'std::vector' : 'T' is not a valid template type argument for parameter '_Ty'

Getting wise, I tried this:

template<typename T> typename std::vector<T>::iterator
              insertIntoVector(std::vector<T>& vec, const T& val)

More Compiler errors:

error C1075: end of file found before the left brace '{'

I'll post my answer below if this question gets unlocked. Otherwise, see my answer on Where and why do I have to put the "template" and "typename" keywords?.

Community
  • 1
  • 1
riderBill
  • 720
  • 6
  • 15
  • use `template typename std::vector::iterator`, as you have a dependent type – vsoftco Oct 17 '14 at 21:22
  • I disagree with this question being a duplicate. First, I searched my *ss off on SO for the answer. How was I to know the magic question to search for? The question is about a **return type** for a **template function** that **returns an iterator** to an **stl container**. Those keywords don't lead me to the cited question. – riderBill Oct 17 '14 at 22:16
  • @vsoftco. typename std::vector::iterator did not work either although the dependent type issue is on the right track. I was posting my answer when I got locked out for a duplicate question. Read the cited question and see if you see what is wrong with your suggestion, or even if it addresses return types. – riderBill Oct 17 '14 at 22:31
  • @T.C. I looked at your cited question again, used my browser search function to look for "return type." The word return is not even in there. vsoftco's comment above isn't quite right either. Apparently your citing doesn't address my (former) question. I was trying to do my part, give something back to the community, but after spending half an hour writing my answer, you kicked me off. Not sure I want to bother trying again. – riderBill Oct 17 '14 at 22:52
  • @riderBill The dependent type question comes up extremely frequently, which is why a number of us close those as duplicates of the canonical question. Those searching could still find the duplicates that would point them to the canonical question and answer. I'd be happy vote to reopen if you can explain what additional ground your answer would cover, because as far as I can tell the compiler errors you posted are all caused by the missing `typename`. – T.C. Oct 17 '14 at 23:09
  • @T.C. Adding the keyword "typename" alone did not fix the problem. I had tried that, as it was clear that the problem was with the compiler not recognizing the return type as a type. The question you cite as well as several others seem to only address template classes, members of template classes, and maybe template members of template classes. My function at the moment is not a member function. I needed slightly different syntax. Also, your question did not come up in my searches (see my comment above). – riderBill Oct 17 '14 at 23:58
  • @T.C. I posted my answer on http://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords. I still think that page is hard to find coming from how I saw the problem. And it did not have the solution (until now). Maybe you could add the *return-type* tag to that page. – riderBill Oct 18 '14 at 00:09
  • Which version of Microsoft's compiler are you using? I tested VS2010 through 2013 and none of them requires parentheses. In fact, it isn't valid C++ syntax at all. – T.C. Oct 18 '14 at 00:59
  • @riderBill can you post a minimal compilable example? i.e. `itr = [some std::vector iterator]` is not valid C++ code, you probably also need `typename` there too. As an example, the following compiles just fine `#include #include // std::lower_bound template typename std::vector::iterator insertIntoVector(std::vector& vec, const T& val) { auto itr = nullptr; return itr; // return iterator to val in vec. } // End of insertIntoVector(); int main(int argc, char const *argv[]) { /* code */ return 0; }` – vsoftco Oct 18 '14 at 01:33
  • @vsoftco Sorry, the stuff in square brackets was pseudocode. I just meant to say that the return value should be of the correct type--added a comment on [Q61024](http://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords/26434669#26434669). See compilable code below. BTW, I previously had a typedef for the return type in the function, but I deleted it as it seemed to clutter more than clarify. Do you think I should put it back in? – riderBill Oct 19 '14 at 06:45
  • @T.C. It makes no sense to me either. And it compiled ok on MSVC 2012 today with or without the parentheses. But yesterday on 2013 I did nothing but enclose the return type in () and it compiled. I'll try it again on 2013 tomorrow or Monday. BTW, while I was playing with it, I tried different groupings: (typename std::vector)::iterator, (typename std::vector)::iterator, and (typename std::vector::iterator) all compiled fine on 2012. I didn't test the resulting code. – riderBill Oct 19 '14 at 06:51
  • @T.C. (Hopefully) last comment. Good stuff on [where-and-why-do-i-have-to-put-the-template-and-typename-keywords](http://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords/26434669#26434669)--recommended reading. But I had a hard time finding it. I didn't even find it (or maybe I didn't recognize it's significance) after picking my tags and looking through the related questions. Can you think of some way to make it come up in a google search with some of the search terms I mentioned above? Maybe add some buzz words in a subtitle? – riderBill Oct 19 '14 at 07:13

1 Answers1

1

Strangely, I had to add parentheses around the return type to get it to compile. That is,

 template<typename T> (typename std::vector<T>::iterator)    // Tested--works as expected.
             insertIntoVector(std::vector<T>& vec, const T& val)

Worked consistently, but

 template<typename T>  typename std::vector<T>::iterator     // Compile errors
             insertIntoVector(std::vector<T>& vec, const T& val)

Gave me problems on MSVC 2013, but compiles on MSVC 2012. I don't know why. Anyone?

The code below compiles and runs correctly on MSVC 2013.

// The following is based on Matt Austern's article,
// "Why you shouldn't use set (and what you should use instead)"
// (http://lafstern.org/matt/col1.pdf).
// I modified it slightly, mostly just reformatting and adding comments,
// but I also changed it to return an iterator to the inserted element.
// Also changed sorted_vector to sortedVector (cammelCase)

#include <vector>
#include <algorithm>  // std::lower_bound


 template<typename T> (typename std::vector<T>::iterator)  // Tested--works as expected.
             insertIntoVector(std::vector<T>& vec, const T& val)
{  // Insert t into vector vec such that v remains in sorted order
   // and all elements of vec are unique (like a set).
   // This only makes sense if the vector elements are
   // maintained in sorted order.
   // A sorted vector might perform better than a set if
   // there are many more access operations than insertions
   // (smaller storage, fast access via [], ... at the cost
   // of much slower insertions).
   // Note: Type T must have a defined < operator.
   /// Todo: overload this function to allow passing a Compare()
   /// function pointer.

   // std::lower_bound() gives log2(N) + O(1) performance.
   typename std::vector<T>::iterator itr
             = lower_bound(vec.begin(), vec.end(), val);
   if ( (vec.end() == itr) || (val < *itr) )
   {  itr = vec.insert(itr, val);
   }
   return itr;  // return iterator to val in vec.
} // End of insertIntoVector();
JasonMArcher
  • 12,386
  • 20
  • 54
  • 51
riderBill
  • 720
  • 6
  • 15
  • When I compiled your code (minus the parens), the only issue I had came from the missing `typename std::` before `vector::iterator` in the body of the function. – T.C. Oct 19 '14 at 07:25
  • @T.C. I tried it on MSVC 2013. It compiles with or without the parens now. I must have screwed something else up on Friday--I'm embarrassed to admit that but I have no other explanation. When I removed the parens on the return type and recompiled, the compiler said "Skipping... (no relevant changes detected)". I guess it sees the () as superfluous. – riderBill Oct 21 '14 at 00:57
  • My compiler did not complain about the missing typename std:: in the body on the itr declaration/definition line, but I added it at your suggestion to improve robustness/portability since you say you had an issue with it. Were you compiling with GCC? I may need this to run on Solaris in the future. I'm not sure how I was getting away w/o a couple of std::'s since I do not have a using std; statement in the file. – riderBill Oct 21 '14 at 00:58