Discussion:
std::vector error
(too old to reply)
Vladimir Grigoriev
2009-12-15 14:57:05 UTC
Permalink
Having the following code

struct Point

{

Point( int i = 0, int j = 0 ): x( i ), y( j ) {}

int x, y;

};

#define MAX_SIZE 10

int _tmain(int argc, _TCHAR* argv[])

{

std::vector<Point> v;

v.reserve( MAX_SIZE );

for ( int i = 0; i < MAX_SIZE; ++i )

{

v.push_back( Point( i, i ) );

}


return 0;

}

I get the error

error C2446: ':' : no conversion from 'const
std::_Vector_iterator<_Ty,_Alloc>' to 'int'
with
[
_Ty=Point,
_Alloc=std::allocator<Point>
]
No user-defined-conversion operator available that can perform this
conversion, or the operator cannot be called

: while compiling class template member function
'std::_Vector_iterator<_Ty,_Alloc>
std::vector<_Ty>::insert(std::_Vector_iterator<_Ty,_Alloc>,const _Ty &)'
with
[
_Ty=Point,
_Alloc=std::allocator<Point>
]



The error occurs inside <vector> in this place



iterator insert(iterator _Where, const _Ty& _Val)

{ // insert _Val at _Where

size_type _Off = size() == 0 ? 0 : _Where - begin();

_Insert_n(_Where, (size_type)1, _Val);

return (begin() + _Off);

}



What is the matter?



Vladimir Grigoriev
Victor Bazarov
2009-12-15 15:12:50 UTC
Permalink
Post by Vladimir Grigoriev
Having the following code
struct Point
{
Point( int i = 0, int j = 0 ): x( i ), y( j ) {}
int x, y;
};
#define MAX_SIZE 10
int _tmain(int argc, _TCHAR* argv[])
{
std::vector<Point> v;
I don't see '#include <vector>' anywhere in this program. Did you post
the actual code?
Post by Vladimir Grigoriev
v.reserve( MAX_SIZE );
for ( int i = 0; i < MAX_SIZE; ++i )
{
v.push_back( Point( i, i ) );
}
return 0;
}
I get the error
error C2446: ':' : no conversion from 'const
std::_Vector_iterator<_Ty,_Alloc>' to 'int'
with
[
_Ty=Point,
_Alloc=std::allocator<Point>
]
No user-defined-conversion operator available that can perform this
conversion, or the operator cannot be called
: while compiling class template member function
'std::_Vector_iterator<_Ty,_Alloc>
std::vector<_Ty>::insert(std::_Vector_iterator<_Ty,_Alloc>,const _Ty &)'
with
[
_Ty=Point,
_Alloc=std::allocator<Point>
]
The error occurs inside <vector> in this place
iterator insert(iterator _Where, const _Ty& _Val)
{ // insert _Val at _Where
size_type _Off = size() == 0 ? 0 : _Where - begin();
_Insert_n(_Where, (size_type)1, _Val);
return (begin() + _Off);
}
What is the matter?
Any chance you're using VC++ v6? If so, you're on your own.

I don't see you use 'insert' in your code anywhere. Are you sure you've
posted the code that you've compiled?

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Vladimir Grigoriev
2009-12-15 15:20:28 UTC
Permalink
Victor, it is a good remark and I have presented already more detailed
information.

Vladimir Grigoriev
Post by Victor Bazarov
Post by Vladimir Grigoriev
Having the following code
struct Point
{
Point( int i = 0, int j = 0 ): x( i ), y( j ) {}
int x, y;
};
#define MAX_SIZE 10
int _tmain(int argc, _TCHAR* argv[])
{
std::vector<Point> v;
I don't see '#include <vector>' anywhere in this program. Did you post
the actual code?
Post by Vladimir Grigoriev
v.reserve( MAX_SIZE );
for ( int i = 0; i < MAX_SIZE; ++i )
{
v.push_back( Point( i, i ) );
}
return 0;
}
I get the error
error C2446: ':' : no conversion from 'const
std::_Vector_iterator<_Ty,_Alloc>' to 'int'
with
[
_Ty=Point,
_Alloc=std::allocator<Point>
]
No user-defined-conversion operator available that can perform
this conversion, or the operator cannot be called
: while compiling class template member function
'std::_Vector_iterator<_Ty,_Alloc>
std::vector<_Ty>::insert(std::_Vector_iterator<_Ty,_Alloc>,const _Ty &)'
with
[
_Ty=Point,
_Alloc=std::allocator<Point>
]
The error occurs inside <vector> in this place
iterator insert(iterator _Where, const _Ty& _Val)
{ // insert _Val at _Where
size_type _Off = size() == 0 ? 0 : _Where - begin();
_Insert_n(_Where, (size_type)1, _Val);
return (begin() + _Off);
}
What is the matter?
Any chance you're using VC++ v6? If so, you're on your own.
I don't see you use 'insert' in your code anywhere. Are you sure you've
posted the code that you've compiled?
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Vladimir Grigoriev
2009-12-15 15:15:19 UTC
Permalink
I am sorry. The initial code is nor complete. I have found that the error
occurs when I add the following template operator

template <typename T>

inline const T operator -( const T &lhs, const T &rhs )

{

return ( T( lhs ) -= rhs );

}

So the code should look the following way

#include "stdafx.h"

#include <iostream>

#include <vector>

struct Point

{

explicit Point( int i = 0, int j = 0 ): x( i ), y( j ) {}

Point( const Point &rhs ): x( rhs.x ), y( rhs.y ) {}

~Point() {}

Point & operator =( const Point &rhs )

{

x = rhs.x; y = rhs.y;

return ( *this );

}

Point & operator -=( const Point &rhs )

{

x -= rhs.x; y -= rhs.y;

return ( *this );

}

Point & operator --()

{

*this -= Point( 1, 1 );

return ( *this );

}

const Point operator --( int )

{

Point tmp = *this;

--*this;

return ( tmp );

}

const Point operator -() const

{

return ( Point( -x, -y ) );

}

int x, y;

};

inline std::ostream & operator <<( std::ostream &os, const Point &rhs )

{

os << "{" << rhs.x << ", " << rhs.y << "}";

return ( os );

}

inline bool operator ==( const Point &lhs, const Point &rhs )

{

return ( ( lhs.x == rhs.x ) && ( lhs.y == rhs.y ) );

}

inline bool operator !=( const Point &lhs, const Point &rhs )

{

return ( !( lhs == rhs ) );

}

template <typename T>

inline const T operator -( const T &lhs, const T &rhs )

{

return ( T( lhs ) -= rhs );

}

#define MAX_SIZE 10

int _tmain(int argc, _TCHAR* argv[])

{

std::vector<Point> v;

v.reserve( MAX_SIZE );

for ( int i = 0; i < MAX_SIZE; ++i )

{

v.push_back( Point( i, i ) );

}


return 0;

}



What is the matter?



Vladimir Grigoriev
Giovanni Dicanio
2009-12-15 15:25:39 UTC
Permalink
Post by Vladimir Grigoriev
So the code should look the following way
[...]
What is the matter?
It seems working OK on VC9 with SP1:

c:\tmp>type test.cpp
#include <iostream>
#include <vector>

struct Point
{
explicit Point( int i = 0, int j = 0 ): x( i ), y( j ) {}

Point( const Point &rhs ): x( rhs.x ), y( rhs.y ) {}

~Point() {}

Point & operator =( const Point &rhs )
{
x = rhs.x; y = rhs.y;

return ( *this );
}

Point & operator -=( const Point &rhs )
{

x -= rhs.x; y -= rhs.y;

return ( *this );
}

Point & operator --()
{
*this -= Point( 1, 1 );

return ( *this );
}

const Point operator --( int )
{
Point tmp = *this;
--*this;

return ( tmp );
}

const Point operator -() const
{
return ( Point( -x, -y ) );
}

int x, y;
};


inline std::ostream & operator <<( std::ostream &os, const Point &rhs )
{
os << "{" << rhs.x << ", " << rhs.y << "}";

return ( os );
}

inline bool operator ==( const Point &lhs, const Point &rhs )
{

return ( ( lhs.x == rhs.x ) && ( lhs.y == rhs.y ) );
}

inline bool operator !=( const Point &lhs, const Point &rhs )
{

return ( !( lhs == rhs ) );
}

template <typename T>
inline const T operator -( const T &lhs, const T &rhs )
{

return ( T( lhs ) -= rhs );
}

#define MAX_SIZE 10

int main(void)
{
std::vector<Point> v;
v.reserve( MAX_SIZE );

for ( int i = 0; i < MAX_SIZE; ++i )
{
v.push_back( Point( i, i ) );
}


return 0;
}

c:\tmp>cl /EHsc /nologo /W4 /MT /O2 /GL test.cpp
test.cpp
Generating code
Finished generating code


Giovanni
Victor Bazarov
2009-12-15 16:29:30 UTC
Permalink
Post by Vladimir Grigoriev
I am sorry. The initial code is nor complete. I have found that the error
occurs when I add the following template operator
template <typename T>
inline const T operator -( const T &lhs, const T &rhs )
{
return ( T( lhs ) -= rhs );
}
So the code should look the following way
[..]
After dropping MS-specific elements from the code I was able to compile
it with Comeau online trial. The code is fine. Consider upgrading your
compiler, maybe?

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Vladimir Grigoriev
2009-12-15 16:42:50 UTC
Permalink
The code must be compiled because it has no any invalid code. It is bug of
the Microsoft realization of vecotrs.

The error occurs in the followin function frim <vector>

iterator insert(iterator _Where, const _Ty& _Val)

{ // insert _Val at _Where

size_type _Off = size() == 0 ? 0 : _Where - begin();

_Insert_n(_Where, (size_type)1, _Val);

return (begin() + _Off);

}



It seems that for the statement

size_type _Off = size() == 0 ? 0 : _Where - begin();

my template minus operator is used. Instead of a size_t value _Where -
begin(); generates const inerator.



Vladimir Grigoriev
Post by Vladimir Grigoriev
I am sorry. The initial code is nor complete. I have found that the error
occurs when I add the following template operator
template <typename T>
inline const T operator -( const T &lhs, const T &rhs )
{
return ( T( lhs ) -= rhs );
}
So the code should look the following way
[..]
After dropping MS-specific elements from the code I was able to compile it
with Comeau online trial. The code is fine. Consider upgrading your
compiler, maybe?
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Bo Persson
2009-12-15 16:34:10 UTC
Permalink
Post by Vladimir Grigoriev
I am sorry. The initial code is nor complete. I have found that the
error occurs when I add the following template operator
template <typename T>
inline const T operator -( const T &lhs, const T &rhs )
{
return ( T( lhs ) -= rhs );
}
This defines an operator- for ANY type. Why do you want to do that?



Bo Persson
Vladimir Grigoriev
2009-12-15 16:45:16 UTC
Permalink
I do that only for my experiance.

Vladimir Grigoriev
Post by Bo Persson
Post by Vladimir Grigoriev
I am sorry. The initial code is nor complete. I have found that the
error occurs when I add the following template operator
template <typename T>
inline const T operator -( const T &lhs, const T &rhs )
{
return ( T( lhs ) -= rhs );
}
This defines an operator- for ANY type. Why do you want to do that?
Bo Persson
Vladimir Grigoriev
2009-12-15 15:18:37 UTC
Permalink
I use Visual C++ 2005 EE.

Vladimir Grigoriev
Leigh Johnston
2009-12-15 15:22:16 UTC
Permalink
Looks ok and compiles fine for me on VC9.

/Leigh
Post by Vladimir Grigoriev
Having the following code
struct Point
{
Point( int i = 0, int j = 0 ): x( i ), y( j ) {}
int x, y;
};
#define MAX_SIZE 10
int _tmain(int argc, _TCHAR* argv[])
{
std::vector<Point> v;
v.reserve( MAX_SIZE );
for ( int i = 0; i < MAX_SIZE; ++i )
{
v.push_back( Point( i, i ) );
}
return 0;
}
I get the error
error C2446: ':' : no conversion from 'const
std::_Vector_iterator<_Ty,_Alloc>' to 'int'
with
[
_Ty=Point,
_Alloc=std::allocator<Point>
]
No user-defined-conversion operator available that can perform this
conversion, or the operator cannot be called
: while compiling class template member function
'std::_Vector_iterator<_Ty,_Alloc>
std::vector<_Ty>::insert(std::_Vector_iterator<_Ty,_Alloc>,const _Ty &)'
with
[
_Ty=Point,
_Alloc=std::allocator<Point>
]
The error occurs inside <vector> in this place
iterator insert(iterator _Where, const _Ty& _Val)
{ // insert _Val at _Where
size_type _Off = size() == 0 ? 0 : _Where - begin();
_Insert_n(_Where, (size_type)1, _Val);
return (begin() + _Off);
}
What is the matter?
Vladimir Grigoriev
Vladimir Grigoriev
2009-12-15 15:27:30 UTC
Permalink
I am sorry. The original code is not complete because I did not know what
part of my code generates the error. I have shown the complete problem code.
I am using VC 2005 C++ EE.

Vladimir Grigoriev
Post by Leigh Johnston
Looks ok and compiles fine for me on VC9.
Vladimir Grigoriev
2009-12-15 15:45:11 UTC
Permalink
It seems like the vector uses my template minus operator.
I think that it is a bug of VC++.

Vladimir Grigoriev
Vladimir Grigoriev
2009-12-15 17:24:31 UTC
Permalink
I think that the problem lies in the definition of operator-() in the class
_Vector_iterator . The right hand side is defined as const _Mybase& _Right.
The compiler sees that _Vector_iterator is used as rhs. So it thinks that my
template operator is more suitable.

Here are some definitions

template<class _Ty,
class _Alloc>
class _Vector_iterator
: public _Vector_const_iterator<_Ty, _Alloc>
{ // iterator for mutable vector
public:
typedef _Vector_iterator<_Ty, _Alloc> _Myt;
typedef _Vector_const_iterator<_Ty, _Alloc> _Mybase;


difference_type operator-(const _Mybase& _Right) const
{ // return difference of iterators
return (*(_Mybase *)this - _Right);
}

Vladimir Grigoriev
So the question now looks the following way: Why is the user template
operator-() used instead of defined in the class _Vector_iterator member
operator
difference_type operator-(const _Mybase& _Right) const
{ // return difference of iterators
return (*(_Mybase *)this - _Right);
}
Vladimir Grigoriev
Victor Bazarov
2009-12-15 17:49:42 UTC
Permalink
I have simulated the situation
#include "stdafx.h"
#include <iostream>
template <typename T>
inline const T operator -( const T &lhs, const T &rhs )
{
// return ( T( lhs ) -= rhs );
std::cout << "template operator - is used.\n";
return ( T() );
}
class A
{
size_t operator -( const A &rhs ) const
{
std::cout << "A::operator - is used.\n";
return ( 0 );
}
};
class B: public A
{
size_t operator -( const A &rhs ) const
{
std::cout << "B::operator - is used.\n";
return ( 1 );
}
};
int _tmain(int argc, _TCHAR* argv[])
{
B b1, b2;
b1 - b2;
return 0;
}
The output is
template operator - is used.
Press any key to continue . . .
Well, of course! The template ::op- has the two operands that are of
the same type. The B::op- requires conversion (albeit standard) for the
second operand, and the A::op- requires conversion for both operands.
Of course the function that does NOT require conversions (only reference
binding) is picked -- its rank is higher for overload resolution.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Vladimir Grigoriev
2009-12-15 17:41:16 UTC
Permalink
I have simulated the situation

#include "stdafx.h"

#include <iostream>



template <typename T>

inline const T operator -( const T &lhs, const T &rhs )

{

// return ( T( lhs ) -= rhs );

std::cout << "template operator - is used.\n";

return ( T() );

}

class A

{

public:

size_t operator -( const A &rhs ) const

{

std::cout << "A::operator - is used.\n";



return ( 0 );

}

};

class B: public A

{

public:

size_t operator -( const A &rhs ) const

{

std::cout << "B::operator - is used.\n";

return ( 1 );

}

};


int _tmain(int argc, _TCHAR* argv[])

{




B b1, b2;


b1 - b2;


return 0;

}



The output is

template operator - is used.
Press any key to continue . . .



Vladimir Grigoriev
Tim Roberts
2009-12-16 05:17:32 UTC
Permalink
Post by Vladimir Grigoriev
I think that the problem lies in the definition of operator-() in the class
_Vector_iterator . The right hand side is defined as const _Mybase& _Right.
The compiler sees that _Vector_iterator is used as rhs. So it thinks that my
template operator is more suitable.
Right. That's what the rules require.

So, do you now concede that the problem is in your code, and not in the
compiler?
--
Tim Roberts, ***@probo.com
Providenza & Boekelheide, Inc.
Vladimir Grigoriev
2009-12-16 10:55:41 UTC
Permalink
No, you are mistaken! The problem is in Microsoft VC++ code. It breaks the
main principle of OOP that a server code should not depend on a client code.
The correct code must use the following C++ construction

iterator insert(iterator _Where, const _Ty& _Val)

{ // insert _Val at _Where

size_type _Off = size() == 0 ? 0 : _Where.operator -( begin() ); //
<== Uses the corresponding member operator explicitly

_Insert_n(_Where, (size_type)1, _Val);

return (begin() + _Off);

}



instead of

iterator insert(iterator _Where, const _Ty& _Val)

{ // insert _Val at _Where

size_type _Off = size() == 0 ? 0 : _Where - begin(); // <=== here is a
bug

_Insert_n(_Where, (size_type)1, _Val);

return (begin() + _Off);

}



It is a bug indeed of the Microsoft implementation of the vector container.



Vladimir Grigoriev
Post by Tim Roberts
Post by Vladimir Grigoriev
I think that the problem lies in the definition of operator-() in the class
_Vector_iterator . The right hand side is defined as const _Mybase& _Right.
The compiler sees that _Vector_iterator is used as rhs. So it thinks that my
template operator is more suitable.
Right. That's what the rules require.
So, do you now concede that the problem is in your code, and not in the
compiler?
--
Providenza & Boekelheide, Inc.
Vladimir Grigoriev
2009-12-16 13:33:04 UTC
Permalink
I have made the following example that to show that it is a bug of the
Microsoft vector implementation and that the member operator - should be
used explicitly.:)

template <typename T>

class A

{

public:

A( T *p = 0 ): ptr( p ) {}

int operator -( const A &rhs ) const

{

return ( static_cast<int>( ptr - rhs.ptr ) );

}

A & operator -=( const A &rhs )

{

if ( ptr > rhs.ptr ) ptr = rhs.ptr;

return ( *this );

}

virtual std::ostream & out( std::ostream &os ) const

{

os << ptr;

return ( os );

}

private:

T *ptr;

};

template <typename T>

class B: public A<T>

{

public:

B( T *p = 0 ): A( p ) {}

int operator -( const A &rhs ) const

{

return ( *( A *)this - rhs );

}

B & operator -=( const B &rhs )

{

*( A *)this -= rhs;

return ( *this );

}

virtual std::ostream & out( std::ostream &os ) const

{

return ( A::out( os ) );

}

};

template <typename T>

std::ostream & operator <<( std::ostream &os, const A<T> &rhs )

{

return ( rhs.out( os ) );

}

int _tmain(int argc, _TCHAR* argv[])

{

const char *cp1 = "ABCD";

const char *cp2 = cp1 + 2;


B<const char> b1( cp1 );

B<const char> b2( cp2 );


std::cout << "( b2 - b1 ) == " << b2 - b1 << std::endl;

std::cout << "b2.operator -( b1 ) == " << b2.operator -( b1 ) <<
std::endl;


return 0;

}



Vladimir Grigoriev
Post by Vladimir Grigoriev
No, you are mistaken! The problem is in Microsoft VC++ code. It breaks the
main principle of OOP that a server code should not depend on a client code.
The correct code must use the following C++ construction
iterator insert(iterator _Where, const _Ty& _Val)
{ // insert _Val at _Where
size_type _Off = size() == 0 ? 0 : _Where.operator -( begin() ); //
<== Uses the corresponding member operator explicitly
_Insert_n(_Where, (size_type)1, _Val);
return (begin() + _Off);
}
instead of
iterator insert(iterator _Where, const _Ty& _Val)
{ // insert _Val at _Where
size_type _Off = size() == 0 ? 0 : _Where - begin(); // <=== here is
a bug
_Insert_n(_Where, (size_type)1, _Val);
return (begin() + _Off);
}
It is a bug indeed of the Microsoft implementation of the vector container.
Vladimir Grigoriev
Vladimir Grigoriev
2009-12-16 13:46:24 UTC
Permalink
I have forgitten to include the operator :)

template <typename T>

inline const T operator -( const T &lhs, const T &rhs )

{

return ( T( lhs ) -= rhs );

}



Vladimir Grigoriev
Post by Vladimir Grigoriev
I have made the following example that to show that it is a bug of the
Microsoft vector implementation and that the member operator - should be
used explicitly.:)
template <typename T>
class A
{
A( T *p = 0 ): ptr( p ) {}
int operator -( const A &rhs ) const
{
return ( static_cast<int>( ptr - rhs.ptr ) );
}
A & operator -=( const A &rhs )
{
if ( ptr > rhs.ptr ) ptr = rhs.ptr;
return ( *this );
}
virtual std::ostream & out( std::ostream &os ) const
{
os << ptr;
return ( os );
}
T *ptr;
};
template <typename T>
class B: public A<T>
{
B( T *p = 0 ): A( p ) {}
int operator -( const A &rhs ) const
{
return ( *( A *)this - rhs );
}
B & operator -=( const B &rhs )
{
*( A *)this -= rhs;
return ( *this );
}
virtual std::ostream & out( std::ostream &os ) const
{
return ( A::out( os ) );
}
};
template <typename T>
std::ostream & operator <<( std::ostream &os, const A<T> &rhs )
{
return ( rhs.out( os ) );
}
int _tmain(int argc, _TCHAR* argv[])
{
const char *cp1 = "ABCD";
const char *cp2 = cp1 + 2;
B<const char> b1( cp1 );
B<const char> b2( cp2 );
std::cout << "( b2 - b1 ) == " << b2 - b1 << std::endl;
std::cout << "b2.operator -( b1 ) == " << b2.operator -( b1 ) <<
std::endl;
return 0;
}
Vladimir Grigoriev
Post by Vladimir Grigoriev
No, you are mistaken! The problem is in Microsoft VC++ code. It breaks
the main principle of OOP that a server code should not depend on a
client code.
The correct code must use the following C++ construction
iterator insert(iterator _Where, const _Ty& _Val)
{ // insert _Val at _Where
size_type _Off = size() == 0 ? 0 : _Where.operator -( begin() ); //
<== Uses the corresponding member operator explicitly
_Insert_n(_Where, (size_type)1, _Val);
return (begin() + _Off);
}
instead of
iterator insert(iterator _Where, const _Ty& _Val)
{ // insert _Val at _Where
size_type _Off = size() == 0 ? 0 : _Where - begin(); // <=== here is
a bug
_Insert_n(_Where, (size_type)1, _Val);
return (begin() + _Off);
}
It is a bug indeed of the Microsoft implementation of the vector container.
Vladimir Grigoriev
Igor Tandetnik
2009-12-16 13:44:18 UTC
Permalink
Post by Vladimir Grigoriev
No, you are mistaken! The problem is in Microsoft VC++ code. It breaks the
main principle of OOP that a server code should not depend on a client code.
This principle cannot be readily applied to STL - all it does is manipulate user-provided classes and naturally depends on their behavior. However, the implementation should avoid _unintended_ points of customization. Unfortunately, C++ makes it difficult to do so.

For discussion of a similar set of issues, see

http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#225
http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#226
http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#229
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1387.htm

These defect reports attempt to plug a particular hole - that of picking up unintended user-defined functions by Koenig lookup. Your case doesn't involve Koenig lookup, so it's different in the letter though similar in spirit. It's not clear to me whether VC2005's implementation is outright non-conforming, but from a quality-of-implementation standpoint it could certainly be improved (which, apparently, it was in later versions).

Having said that, defining a generally-applicable templated overloaded operator in global scope is probably not the best idea. It's too easy to pick it up by accident.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not necessarily a good idea. It is hard to be sure where they are going to land, and it could be dangerous sitting under them as they fly overhead. -- RFC 1925
Vladimir Grigoriev
2009-12-16 13:50:29 UTC
Permalink
In my opinion it is a bug indeed because using explicitly the member
operator resolves the problem.

size_type _Off = size() == 0 ? 0 : _Where.operator -( begin() );

Vladimir Grigoriev
Post by Vladimir Grigoriev
No, you are mistaken! The problem is in Microsoft VC++ code. It breaks the
main principle of OOP that a server code should not depend on a client code.
This principle cannot be readily applied to STL - all it does is manipulate
user-provided classes and naturally depends on their behavior. However, the
implementation should avoid _unintended_ points of customization.
Unfortunately, C++ makes it difficult to do so.

For discussion of a similar set of issues, see

http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#225
http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#226
http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#229
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1387.htm

These defect reports attempt to plug a particular hole - that of picking up
unintended user-defined functions by Koenig lookup. Your case doesn't
involve Koenig lookup, so it's different in the letter though similar in
spirit. It's not clear to me whether VC2005's implementation is outright
non-conforming, but from a quality-of-implementation standpoint it could
certainly be improved (which, apparently, it was in later versions).

Having said that, defining a generally-applicable templated overloaded
operator in global scope is probably not the best idea. It's too easy to
pick it up by accident.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not necessarily
a good idea. It is hard to be sure where they are going to land, and it
could be dangerous sitting under them as they fly overhead. -- RFC 1925
Vladimir Grigoriev
2009-12-16 13:58:54 UTC
Permalink
Post by Vladimir Grigoriev
In my opinion it is a bug indeed because using explicitly the member
operator resolves the problem.
size_type _Off = size() == 0 ? 0 : _Where.operator -( begin() );
Vladimir Grigoriev
I.e. I wanted to say that when an operator of a derived class uses a
reference to a base class as a parameter it leaves a hole in the opration
implementation. In fact this means that the designer is saying: "I am not
responsible if you will use a reference to the deribed class as an parameter
of the operator. In this case you may use any ypur own implementation of the
operator."

Vladimir Grigoriev
Igor Tandetnik
2009-12-16 14:29:00 UTC
Permalink
Post by Vladimir Grigoriev
I.e. I wanted to say that when an operator of a derived class uses a
reference to a base class as a parameter it leaves a hole in the opration
implementation. In fact this means that the designer is saying: "I am not
responsible if you will use a reference to the deribed class as an parameter
of the operator. In this case you may use any ypur own implementation of the
operator."
Yes, that's an example of an unintended point of customization. For discussion, see

http://www.ddj.com/cpp/184401876
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1691.html
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2001/n1296.asc
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not necessarily a good idea. It is hard to be sure where they are going to land, and it could be dangerous sitting under them as they fly overhead. -- RFC 1925
Igor Tandetnik
2009-12-16 14:06:53 UTC
Permalink
Post by Vladimir Grigoriev
In my opinion it is a bug indeed because using explicitly the member
operator resolves the problem.
I don't quite understand this reasoning. The definition of "bug" is not "there exists an alternative way of performing the same task that I like better", it's "the current way of performing the task violates the specification". You can't say: it's a bug _because_ I know how to fix it. You should say: it's a bug because it violates requirement X, and luckily I happen to know how to fix it.

And I can't find anything in the specification (the C++ standard) that would explicitly prohibit the current implementation. Which, arguably, is a defect in the standard itself. In fact, a similar problem was recognized as a defect and the wording clarified accordingly, but it appears that the fix is too narrow.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not necessarily a good idea. It is hard to be sure where they are going to land, and it could be dangerous sitting under them as they fly overhead. -- RFC 1925
Vladimir Grigoriev
2009-12-16 14:24:01 UTC
Permalink
I am naming it as a bug becase the designer thought one thing but had done
another thing. He meant using of a concrete member operator however had
written the expression in general form given the freedom in interpretation
of the expression.

In fact the expression

size_type _Off = size() == 0 ? 0 : _Where -begin();

is not fully defined because there is not in the class definition of _Myt
such operator as

difference_type operator-(const _Myt& _Right) const
{ // return difference of iterators
return (*(_Mybase *)this - _Right);
}

There is an operator

difference_type operator-(const _Mybase& _Right) const
{ // return difference of iterators
return (*(_Mybase *)this - _Right);
}

where _Mybase is a base class for _Myt..

It is a bug because the designer should either include the operator

difference_type operator-(const _Myt& _Right) const
{ // return difference of iterators
return (*(_Mybase *)this - _Right);
}
along with the original operator there Mybase& is used, or use the form of
specifying the member operator explicitly in the expression.

Vladimir Grigoriev




Vladimir Grigoriev
Post by Vladimir Grigoriev
In my opinion it is a bug indeed because using explicitly the member
operator resolves the problem.
I don't quite understand this reasoning. The definition of "bug" is not
"there exists an alternative way of performing the same task that I like
better", it's "the current way of performing the task violates the
specification". You can't say: it's a bug _because_ I know how to fix it.
You should say: it's a bug because it violates requirement X, and luckily I
happen to know how to fix it.

And I can't find anything in the specification (the C++ standard) that would
explicitly prohibit the current implementation. Which, arguably, is a defect
in the standard itself. In fact, a similar problem was recognized as a
defect and the wording clarified accordingly, but it appears that the fix is
too narrow.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not necessarily
a good idea. It is hard to be sure where they are going to land, and it
could be dangerous sitting under them as they fly overhead. -- RFC 1925
Vladimir Grigoriev
2009-12-16 14:41:26 UTC
Permalink
I.e. the main question is Why did the designer decide that in the expression

size_type _Off = size() == 0 ? 0 : _Where -begin();

will be used his operator?! He is only *one* of at least two pretendents to
take part in the evolution of the expression. :)

Vladimir Grigoriev
Post by Vladimir Grigoriev
I am naming it as a bug becase the designer thought one thing but had done
another thing. He meant using of a concrete member operator however had
written the expression in general form given the freedom in interpretation
of the expression.
In fact the expression
size_type _Off = size() == 0 ? 0 : _Where -begin();
is not fully defined because there is not in the class definition of _Myt
such operator as
difference_type operator-(const _Myt& _Right) const
{ // return difference of iterators
return (*(_Mybase *)this - _Right);
}
There is an operator
difference_type operator-(const _Mybase& _Right) const
{ // return difference of iterators
return (*(_Mybase *)this - _Right);
}
where _Mybase is a base class for _Myt..
It is a bug because the designer should either include the operator
difference_type operator-(const _Myt& _Right) const
{ // return difference of iterators
return (*(_Mybase *)this - _Right);
}
along with the original operator there Mybase& is used, or use the form
of specifying the member operator explicitly in the expression.
Vladimir Grigoriev
Igor Tandetnik
2009-12-16 14:51:27 UTC
Permalink
Post by Vladimir Grigoriev
I.e. the main question is Why did the designer decide that in the expression
size_type _Off = size() == 0 ? 0 : _Where -begin();
will be used his operator?!
Most likely, the designer has simply overlooked the possibility of accidentally picking up a wrong overload. Which oversight has been apparently corrected in later versions. What more can you expect?
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not necessarily a good idea. It is hard to be sure where they are going to land, and it could be dangerous sitting under them as they fly overhead. -- RFC 1925
Igor Tandetnik
2009-12-16 14:48:32 UTC
Permalink
Post by Vladimir Grigoriev
It is a bug because the designer should either include the operator
difference_type operator-(const _Myt& _Right) const
{ // return difference of iterators
return (*(_Mybase *)this - _Right);
}
along with the original operator there Mybase& is used, or use the form of
specifying the member operator explicitly in the expression.
Again, you are saying: it's a bug _because_ the implementation should be written differently. This confuses cause and effect: "the wind is blowing because trees are shaking." The causality should go the other way round: the implementation should be written differently _because_ the current implementation has a bug. This of course still requires one to demonstrate that the current implementation does in fact have a bug, and not just a behavior that you might not like but that is nevertheless conforming.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not necessarily a good idea. It is hard to be sure where they are going to land, and it could be dangerous sitting under them as they fly overhead. -- RFC 1925
Vladimir Grigoriev
2009-12-15 17:13:16 UTC
Permalink
So the question now looks the following way: Why is the user template
operator-() used instead of defined in the class _Vector_iterator member
operator
difference_type operator-(const _Mybase& _Right) const

{ // return difference of iterators

return (*(_Mybase *)this - _Right);

}



Vladimir Grigoriev
Continue reading on narkive:
Loading...