From: Daniel Krügler on
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
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
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
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
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! ]