Prev: Job for Boost filtered iterators ???
Next: State of N2801: initializer lists and move semantics
From: Daniel Krügler on 4 Jul 2010 07:04 On 4 Jul., 10:42, Rem <therealr...(a)gmail.com> wrote: > Please take a look at this code: > > class A > { > public: > > template<class XIter> > A(const XIter begin, const XIter beyond) > {} This function signature is equivalent to A(XIter begin, XIter beyond) {} for the compiler. All top-level cv-qualifiers of parameters are ignored. > }; > #include <vector> > > int main(int argc, char* argv[]) > { > std::vector<int> integers; > > A a1( integers.begin(), integers.end() );//No problem This is no problem, because both arguments have the same type. The deduced type of the template parameter for either argument of the constructor template is exactly this type. > std::vector<int>::const_iterator i( ++( integers.begin() ) );// > compiler doesn't like const_iterator here > A a2( i, integers.end() );//error C2660: 'A::A' : function does not > take 2 arguments > > return 0; > > } > > What happened here is that in a2 constructor call Visual C++ 2008 was > unable to choose the const version of std::vector<T>::end() - or so I > guess. The error message is very confusing. Your guess is wrong. What happens here, is that you provide two arguments of different type: The first of type std::vector<int>::const_iterator and the second of type std::vector<int>::iterator During type deduction of above constructor template the first result for the template parameter XIter thus differs from the second, and thus this function won't be selected. > Do you know how I can make sure that the const_iterator is picked as a > template argument instead of iterator? you could use a cast for the second argument as shown here: A a2( i, const_cast<const std::vector<int>&>(integers).end() ); If you have a C++0x library, you can directly use the member function cend: A a2( i, integers.cend() ); HTH & Greetings from Bremen, Daniel Kr�gler -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Dragan Milenkovic on 5 Jul 2010 04:04 Bo Persson wrote: > Rem wrote: >> Please take a look at this code: >> >> >> class A >> { >> public: >> >> template<class XIter> >> A(const XIter begin, const XIter beyond) >> {} >> }; >> >> >> #include <vector> >> >> >> int main(int argc, char* argv[]) >> { >> std::vector<int> integers; >> >> A a1( integers.begin(), integers.end() );//No problem >> >> std::vector<int>::const_iterator i( ++( integers.begin() ) );// >> compiler doesn't like const_iterator here >> A a2( i, integers.end() );//error C2660: 'A::A' : function does not >> take 2 arguments >> >> return 0; >> } >> >> What happened here is that in a2 constructor call Visual C++ 2008 >> was unable to choose the const version of std::vector<T>::end() - >> or so I guess. The error message is very confusing. >> Do you know how I can make sure that the const_iterator is picked >> as a template argument instead of iterator? > > Right now, you have to call end() on a const vector to get a > const_iterator. You could possibly make 'integers' const, or form a > const reference to it: > > const std:vector<int>& const_integer = integer; IMHO, it would be better to cast the result of end() static_cast<std::vector<int>::const_iterator>(integers.end()); or even better (IMHO cleaner) to use a variable: std::vector<int>::const_iterator e = integers.end(); Compiler will optimize it nicely. Another approach would be: template <typename XIter> A make_A(const XIter & a, const XIter & b) { return A(a, b); } A a = make_A<std::vector<int>::const_integer>(i, integers.end()); And finally, you don't need "++", you can use integers.begin()+1. Anyway, the compiler will never choose the const version of end(), because it is strictly defined by standard what happens when you call an overloaded function on a mutable object. The need for all these inelegant solutions turned on a yellow led in my head. Are you sure that A shouldn't be a template? Can it really be constructed with any pair of iterators? I'm guessing that in your case it can, but I had to mention it and reset my led. -- Dragan [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: cpp4ever on 5 Jul 2010 10:45 On 07/04/2010 09:42 AM, Rem wrote: > Please take a look at this code: > > > class A > { > public: > > template<class XIter> > A(const XIter begin, const XIter beyond) > {} > }; > > > #include <vector> > > > int main(int argc, char* argv[]) > { > std::vector<int> integers; > > A a1( integers.begin(), integers.end() );//No problem > > std::vector<int>::const_iterator i( ++( integers.begin() ) );// > compiler doesn't like const_iterator here > A a2( i, integers.end() );//error C2660: 'A::A' : function does not > take 2 arguments > > return 0; > } > > What happened here is that in a2 constructor call Visual C++ 2008 was > unable to choose the const version of std::vector<T>::end() - or so I > guess. The error message is very confusing. > Do you know how I can make sure that the const_iterator is picked as a > template argument instead of iterator? > Personally I would never create a template definition like that. But a simple solution to your problem would be the use of a const reference std::vector<int> integers; const std::vector<int> &r = integers; A a1( integers.begin(), integers.end() );//No problem // compiler doesn't like const_iterator here std::vector<int>::const_iterator i( ++( integers.begin() ) ); // will work as r.end() will return a const_iterator A a2( i, r.end() ); return 0; HTH cpp4ever -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Seungbeom Kim on 5 Jul 2010 22:07 On 2010-07-05 12:04, Dragan Milenkovic wrote: > Bo Persson wrote: >> Right now, you have to call end() on a const vector to get a >> const_iterator. You could possibly make 'integers' const, or form a >> const reference to it: >> >> const std:vector<int>& const_integer = integer; > > IMHO, it would be better to cast the result of end() > > static_cast<std::vector<int>::const_iterator>(integers.end()); > > or even better (IMHO cleaner) to use a variable: > > std::vector<int>::const_iterator e = integers.end(); > > Compiler will optimize it nicely. Why would it be "better" than calling .end() on a const vector? > And finally, you don't need "++", you can use integers.begin()+1. Correct in the case of std::vector or other containers that produce random-access iterators, but not in general: e.g. +1 won't work with std::list. On the other hand, ++ doesn't work if the iterator turns out to be a raw pointer, which is certainly possible in the case of std::vector. The correct way is to assign the iterator value to a variable and increment it: std::vector<int>::const_iterator i = integers.begin(); ++i; or use boost::next, or std::next in C++0x. std::vector<int>::const_iterator i = boost::next(integers.begin()); std::vector<int>::const_iterator i = std::next(integers.begin()); -- Seungbeom Kim [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Dragan Milenkovic on 6 Jul 2010 11:17 Seungbeom Kim wrote: > On 2010-07-05 12:04, Dragan Milenkovic wrote: >> Bo Persson wrote: >>> Right now, you have to call end() on a const vector to get a >>> const_iterator. You could possibly make 'integers' const, or form a >>> const reference to it: >>> >>> const std:vector<int>& const_integer = integer; >> IMHO, it would be better to cast the result of end() >> >> static_cast<std::vector<int>::const_iterator>(integers.end()); >> >> or even better (IMHO cleaner) to use a variable: >> >> std::vector<int>::const_iterator e = integers.end(); >> >> Compiler will optimize it nicely. > > Why would it be "better" than calling .end() on a const vector? Well, it wasn't. At that moment I was thinking that my line expresses the intention, but after thinking it through, I guess that both lines do. It's just a matter of preference. Therefore, I apologize. I like code that doesn't require additional comments to make it understandable. // introducing e as a const_iterator of the end() std::vector<int>::const_iterator e = integers.end(); // introducing a const "view" of integers for future purposes const std:vector<int>& const_integer = integer; It's just that "future purposes" here was needed only in order to make another code behave correctly and not for the logic itself. This reason was not obvious from the above line itself. Hm... does mine fail to? Now I'm not sure... Maybe I would stick with make_A... Anyway, what Bo Persson suggested is certainly better with respect to performance, as reference will be optimized away. Sorry again. >> And finally, you don't need "++", you can use integers.begin()+1. > > Correct in the case of std::vector or other containers that produce > random-access iterators, but not in general: e.g. +1 won't work with > std::list. I was only suggesting it in case that OP wasn't familiar with it. I didn't like where ++ was placed. You have provided the complete explanation and examples. -- Dragan [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
First
|
Prev
|
Pages: 1 2 Prev: Job for Boost filtered iterators ??? Next: State of N2801: initializer lists and move semantics |