From: Rem on
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?

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Bo Persson on
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;

A a2(i, const_integer.end();


In C++0x (and Visual C++ 2010) the standard containers also have
cbegin() and cend() members, that always return const_iterators. Help
is on its way!



Bo Persson



--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Paul Bibbings on

Rem <therealremi(a)gmail.com> writes:

> 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?

As you might expect when you think a little more about it, the
std::vector member functions begin() and end() exist each as a pair of
overloads (const and non-const):

namespace std {
template<class T, class Allocator = allocator<T> >
class vector {
public:
// ...
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
// ...
};
}

The non-const overloads return an iterator and the const overloads
return a const_iterator. As is the nature of when and how selection
is
made between such overloads, the difference is the constness (or
otherwise) of the std::vector instance on which the particular method
is
invoked.

> A a2( i, integers.end() );// error C2660: 'A::A' : function does not
> // take 2 arguments

Here, i is a const_iterator. However, since end() is called on a
non-const std::vector<int>, this call will produce an iterator. Since
the types of the two arguments to the constructor call are then
different the invocation fails to find the constructor which is singly
parameterized on XIter. Thus the error, as given, doesn't relate to
the
constructor at all but is rather a failure against the compiler-
generated
copy-constructor A(const A&).

Although I do not suggest this as the way to correct your example, the
following illustrates what is going on here:

int main()
{
std::vector<int> integers;
std::vector<int>::const_iterator i(++(integers.begin()));
const std::vector<int>& integers_cref = integers;
A a2(i, integers_cref.end()); // Works: const_iterator for
arg2
}

Also, in your example you have declared the parameters to the
constructor for A to be of type const XIter. This is almost certainly
not what you want, either for iterators or for const_iterators, since
you will not then be able to use the increment/decrement/etc.
operators
upon them.

Regards

Paul Bibbings

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Stuart Golodetz on
On 04/07/2010 09:42, 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?

The non-const end() method gets called because integers isn't const. To call the const version, you can do e.g.

A a2(i, const_cast<const std::vector<int>&>(integers).end());

Or clearer:

const std::vector<int>& cintegers = integers;
A a2(i, cintegers.end());

I think I'm right in saying that cbegin() and cend() methods have been added to things like std::vector in C++0x to get around this sort of issue.

Regards,
Stu

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Pete Becker on
On 2010-07-03 22:42:26 -0400, Rem said:

> 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.

Don't guess. Learn the rules. The template constructor takes two arguments of the same type. The code passes two different types: the first argument has type const_iterator and the second is iterator.

The choice of an overloaded function depends on the arguments, not on how the result is used. The compiler picks the non-const version of end() because the integers object is not const.

The old way of getting around this was static_cast<const std::vector<T>&>(integers).end(). The new way is integers.cend().

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The Standard C++ Library Extensions: a Tutorial and Reference (www.petebecker.com/tr1book)



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]