Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

VC8 compiler behavior?

11 views
Skip to first unread message

Sam Stump

unread,
Aug 21, 2006, 8:33:28 PM8/21/06
to
The code below does not compile with VC8. The error is:

sample.cpp(36) : error C2679: binary '<<' : no operator found which takes
a right-hand operand of type 'const std::vector<_Ty>' (or there is no
acceptable conversion)
with
[
_Ty=int
]

but it is clearly there. Is this conformant behavior or a bug?

================= begin code =====================
// sample.cpp

#include <vector>
#include <iostream>

// move the operator below inside the namespace, then it will compile ...
template <class T>
std::ostream& operator<<(std::ostream& ostr, const std::vector<T>& v)
{
// output comma delimited vector elements ...
std::vector<T>::const_iterator end = v.end();
for (std::vector<T>::const_iterator it = v.begin(); it != end; ++it) {
ostr << *it;
if (it + 1 != end) ostr << ", ";
}
return ostr;
}

namespace formatter {

template <class T>
class bracketed {
public:
bracketed(const T& t) : value(t) {}
const T& value;

private:
// not implemented ...
bracketed<T>& operator=(const bracketed<T>&);
};

template <class T>
std::ostream& operator<<(std::ostream& ostr, const bracketed<T>& v)
{
// enclose value in brackets ...
return ostr << '[' << v.value << ']';
}
};

int main()
{
using formatter::bracketed;

// easy example ...
int x = 21014;
std::cout << bracketed<int>(x) << std::endl;

// more complicated example ...
std::vector<int> v;
v.push_back(2);
v.push_back(1);
v.push_back(0);
v.push_back(1);
v.push_back(4);

std::cout << bracketed<std::vector<int> >(v) << std::endl;
}

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

dasjotre

unread,
Aug 22, 2006, 10:27:37 AM8/22/06
to
compiler first looks at the enclosing namespace and then into std
namespace because vector template is from there (ADL) and it finds
many '<<' operators that don't fit the purpose. because of the ADL
rules it doesn't look any further.

> // move the operator below inside the namespace, then it will compile ...

and that would be the solution for it (the most complete solution
would be putting it inside std namespace)

<snip>

dasjotre

unread,
Aug 22, 2006, 10:28:12 AM8/22/06
to
>> and that would be the solution for it (the most complete solution would
be
>> putting it inside std namespace)
don't!

Earl Purple

unread,
Aug 22, 2006, 10:28:32 AM8/22/06
to

Sam Stump wrote:

> The code below does not compile with VC8. The error is:
>
> sample.cpp(36) : error C2679: binary '<<' : no operator found which takes
> a right-hand operand of type 'const std::vector<_Ty>' (or there is no
> acceptable conversion)
> with
> [
> _Ty=int
> ]
>
> but it is clearly there. Is this conformant behavior or a bug?
>
================= begin code =====================
> // sample.cpp
>
> #include <vector>
> #include <iostream>
>
> // move the operator below inside the namespace, then it will compile ...
> template <class T>
> std::ostream& operator<<(std::ostream& ostr, const std::vector<T>& v)
> {
> // output comma delimited vector elements ...
> std::vector<T>::const_iterator end = v.end();
> for (std::vector<T>::const_iterator it = v.begin(); it != end; ++it) {
> ostr << *it;
> if (it + 1 != end) ostr << ", ";
> }
> return ostr;
> }


//etc
As far as I am aware this is conformant, you can only overload
operators if one of the types is your own, and neither of them are,
because vector belongs in namespace std. You should therefore write a
wrapper. For output this is easy enough.

template < typename SEQ >
class const_sequence_wrapper
{
public:
// put some typedefs here

const SEQ & seq;
/*explicit*/ const_sequence_wrapper( const SEQ & seq_in ) : seq(
seq_in )
{
}

// define begin() and end()
};

then implement operator<< in terms of that. In fact now we've created a
wrapper for the purpose of printing, we can specialise it with extra
parameters regarding how we will output it, eg what delimiter we use,
any "beginning of sequence" and "end of sequence" markers (the latter
is particularly useful).

You may wish, for example, to use tab as delimiter and new-line as
end-of-sequence.

Jack Klein

unread,
Aug 22, 2006, 10:21:20 AM8/22/06
to
On 21 Aug 2006 20:33:28 -0400, Sam Stump
<sMaUmDuDeYl...@verizon.net> wrote in comp.lang.c++.moderated:

> The code below does not compile with VC8. The error is:
>
> sample.cpp(36) : error C2679: binary '<<' : no operator found which takes
> a right-hand operand of type 'const std::vector<_Ty>' (or there is no
> acceptable conversion)
> with
> [
> _Ty=int
> ]
>
> but it is clearly there. Is this conformant behavior or a bug?

[snip]

Almost certainly not the problem you are questioning, but your program
is ill-formed and has undefined behavior. Your code is not allowed to
define identifiers with a leading underscore followed by an upper case
latter, or containing two consecutive underscores anywhere within
them.

All identifiers fitting these patterns are reserved for the
implementation in all contexts.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html

Hrayr BABAJANYAN

unread,
Aug 22, 2006, 10:24:35 AM8/22/06
to
Hi,

The following simplified code emulates the problem:

// >>>>>>>>> begin
namespace M
{
class A {};
class B {};
void f(A, int);
}

void f(M::A, M::B);

namespace N
{
struct D
{
M::B b;
};

void f(M::A a, D d)
{
f(a, d.b);
// should look in current namespace, in namespace M
// where A is declared and in global namespace (but does not)

// error message in VC8:
// error C2665: 'N::f' : none of the 2 overloads could convert all
the argument types
// could be 'void M::f(M::A,int)' [found using argument-dependent
lookup]
// or 'void N::f(M::A,N::D)'
}
}

int main()
{
f(M::A(), N::D());
return (0);
}
// <<<<<<<<< end

It look really strange to me (looks mor like a bug) that the name
lookup
algorithm does not find the matching global function
(3.4.2 Argument-dependent name lookup [basic.lookup.koenig])

"...the set of declarations found by the lookup of the function name
is the union of the set of declarations found using ordinary
unqualified
lookup and the set of declarations found in the namespaces and classes
associated with the argument types."

(BTW: the same problem is present while compiling with gcc 3.2.2)

Cheers!
--
Hrayr

Radu

unread,
Aug 22, 2006, 11:38:43 AM8/22/06
to
Is conformant.
The "global namespace" doesn't participate in the name lookup, so you
have to give your function a hint, like:

template <class T>
std::ostream& operator<<(std::ostream& ostr, const bracketed<T>& v)
{

using ::operator << ;
return ostr << '[' << v.value << ']';
}


HTH

Sam

unread,
Aug 22, 2006, 11:37:47 AM8/22/06
to
{ overquoted sigs trimmed. -mod }

Jack Klein wrote:
> On 21 Aug 2006 20:33:28 -0400, Sam Stump
> <sMaUmDuDeYl...@verizon.net> wrote in comp.lang.c++.moderated:
>
> > The code below does not compile with VC8. The error is:
> >
> > sample.cpp(36) : error C2679: binary '<<' : no operator found which
takes
> > a right-hand operand of type 'const std::vector<_Ty>' (or there is no
> > acceptable conversion)
> > with
> > [
> > _Ty=int
> > ]
> >
> > but it is clearly there. Is this conformant behavior or a bug?
>
> [snip]
>
> Almost certainly not the problem you are questioning, but your program
> is ill-formed and has undefined behavior. Your code is not allowed to
> define identifiers with a leading underscore followed by an upper case
> latter, or containing two consecutive underscores anywhere within
> them.
>
> All identifiers fitting these patterns are reserved for the
> implementation in all contexts.
>
> --
> Jack Klein

Thanks for the advice, but that IS the implementation's identifier, not
mine!

Sam

kanze

unread,
Aug 22, 2006, 11:51:31 AM8/22/06
to
Jack Klein wrote:
> On 21 Aug 2006 20:33:28 -0400, Sam Stump
> <sMaUmDuDeYl...@verizon.net> wrote in comp.lang.c++.moderated:

> > The code below does not compile with VC8. The error is:

> > sample.cpp(36) : error C2679: binary '<<' : no operator found which
takes
> > a right-hand operand of type 'const std::vector<_Ty>' (or there is no
> > acceptable conversion)
> > with
> > [
> > _Ty=int
> > ]

> > but it is clearly there. Is this conformant behavior or a bug?

> [snip]

> Almost certainly not the problem you are questioning, but your
> program is ill-formed and has undefined behavior. Your code
> is not allowed to define identifiers with a leading underscore
> followed by an upper case latter, or containing two
> consecutive underscores anywhere within them.

His code doesn't. Thanks to templates, the actual error occurs
somewhere in the instatiation of a template in the standard
library. Since the standard library is part of the
implementation, it has a right to these identifiers, and in
fact, must use them for any symbol not defined in the standard
library.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

kanze

unread,
Aug 22, 2006, 1:23:25 PM8/22/06
to
dasjotre wrote:

> compiler first looks at the enclosing namespace and then into
> std namespace because vector template is from there (ADL) and
> it finds many '<<' operators that don't fit the purpose.
> because of the ADL rules it doesn't look any further.

According to §3.4.2, you've got it backwards. The compiler
should only apply ADL to increase the set of callable functions.
Of course, templates change the rules somewhat. I'll admit that
I don't understand the rules well enough to be sure, but from my
reading of §14.6.4.2, I would have though his code legal, since
the function he is looking for is delcared before the template
definition, and is visible in the templat definition context.

Still, g++ disagrees with me, and from experience, it's right
more often than I am. But I would like an explication as to why
the standard unqualified lookup in the template definition
context doesn't find the operator, or why this lookup isn't used
in this case.

> > // move the operator below inside the namespace, then it will compile ...

> and that would be the solution for it (the most complete
> solution would be putting it inside std namespace)

Which is formally banned. Worse, it means that other users will
see it, which you definitly want to avoid.

Personally, I think the preferred solution would be to create a
class comma_separated_list (where the actual character used for
the comma is locale dependant), along the lines of bracketed,
and use that.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Gennaro Prota

unread,
Aug 22, 2006, 7:54:32 PM8/22/06
to
On 22 Aug 2006 13:23:25 -0400, "kanze" <ka...@gabi-soft.fr> wrote:

>I'll admit that
>I don't understand the rules well enough to be sure,

Who does :-)

>but from my
>reading of §14.6.4.2, I would have though his code legal, since
>the function he is looking for is delcared before the template
>definition, and is visible in the templat definition context.

The issue is what is visible from the context of

std::ostream& operator<<(std::ostream&, const bracketed<T>&) (*)

Of course both std and formatter are associated with "v.value" within
it. As to the other user-defined operator<< (the one for vectors), it
is in the global namespace but it is never invoked with arguments
whose type is declared there, so in this example it is never found via
ADL (and it can't be found by unqualified lookup either, as it is
invoked from a function that has its same name).

More in detail, let's consider the original code and, in order of
appearance, the two calls in main(); the issue is resolving the call
having v.value as right-hand expression

(1) v.value has type int: unqualified lookup finds (*) itself;
ADL finds (*) again and the std version, which is clearly the
best match.

(2) v.value has type vector<int> but nothing has changed from
the point of view of lookup: the candidates are the same as
in the previous case. Obviously there's no match.

When the first user-defined operator<< is moved into namespace
formatter that namespace kicks in as associated namespace for v.value,
which explains the successful resolution. In short if it works it's
always due to ADL, as ordinary lookup never finds the right choice: it
always finds itself.

This is an analogous, simpler, example, where "<<" is actually named
"f":

#include <ostream>
#include <iostream>

void f(int) {}

namespace S {

struct X { int a; X() : a(0) {} };

template <typename T>
void f(const T& t)
{
f(t.a); // doesn't find f(int)
}

}

int main()
{
S::X x;
f(x);
}


PS: I intentionally omitted that in the original code <ostream> should
be included; it also misses a couple of typename-s. Strictly speaking
it invokes undefined behavior.

--
Gennaro Prota

kanze

unread,
Aug 23, 2006, 9:19:11 AM8/23/06
to
Gennaro Prota wrote:
> On 22 Aug 2006 13:23:25 -0400, "kanze" <ka...@gabi-soft.fr> wrote:

[...]


> >but from my
> >reading of §14.6.4.2, I would have though his code legal, since
> >the function he is looking for is delcared before the template
> >definition, and is visible in the templat definition context.

> The issue is what is visible from the context of

> std::ostream& operator<<(std::ostream&, const bracketed<T>&) (*)

> Of course both std and formatter are associated with "v.value" within
> it. As to the other user-defined operator<< (the one for vectors), it
> is in the global namespace but it is never invoked with arguments
> whose type is declared there, so in this example it is never found via
> ADL (and it can't be found by unqualified lookup either, as it is
> invoked from a function that has its same name).

The part in the parentheses is the what I'd missed. For some
reason, I didn't think of unqualified lookup finding the
function itself.

So if instead of being called from operator<<, the operator were
called from a function called f, and there were no operator<< in
the formatter namespace, the compiler would have found the
operator<< in global namespace.

(I've had problems myself with functions not being found in such
cases, but in every case, the function in question was after the
template definition, and could not be found by unqualified
lookup because of that.)

[...]


> PS: I intentionally omitted that in the original code <ostream> should
> be included; it also misses a couple of typename-s. Strictly speaking
> it invokes undefined behavior.

I noticed that as well. That I had to correct it to compile it
with my version of g++. But of course, that wasn't the issue.
(On the other hand, it's probably worth mentionning the
typename's, if only because it will cause the original poster
problems with newer compilers.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

tpo...@mail.ru

unread,
Aug 23, 2006, 9:32:51 AM8/23/06
to
Hello, Sam.

> The code below does not compile with VC8.

I do not have VC8, so let's use comeau online:
First of all, small fixes:
#include <vector>
#include <iostream>

// move the operator below inside the namespace, then it will compile
...
template <class T>
std::ostream& operator<<(std::ostream& ostr, const std::vector<T>& v)
{
// output comma delimited vector elements ...

typename std::vector<T>::const_iterator end = v.end();
for (typename std::vector<T>::const_iterator it = v.begin(); it !=

Now, if we try to compile this code with comeau online, we'll have
errors:
"ComeauTest.c", line 32: error: no operator "<<" matches these operands
operand types are: std::basic_ostream<char,
std::char_traits<char>> << const std::vector<int,
std::allocator<int>>
return ostr << '[' << v.value << ']';
^
detected during instantiation of "std::ostream
&formatter::operator<<(std::ostream &, const
formatter::bracketed<T> &) [with T=std::vector<int,
std::allocator<int>>]" at line 49
Ok, that's because you have templates and two-phase name lookup:

The first phase:

template <class T>
std::ostream& operator<<(std::ostream& ostr, const bracketed<T>& v)
{
// enclose value in brackets ...

return ostr << '[' << v.value << ']'; //(*)
}

In (*), compiler looks for operator << and finds only


std::ostream& operator<<(std::ostream& ostr, const bracketed<T>& v)

(after he finds it, compiler stops lookup and doesn't check enclosing
namespace (global)).

The second phase:

During the second stage compiler uses ADL and cannot find global
operator<<.

For example, if you change operator's name (operator >>), your example
will be compilable by comeau (yes, I know, such usage of operator >> is
stupid :) ):

#include <vector>
#include <iostream>

// move the operator below inside the namespace, then it will compile
...
template <class T>
std::ostream& operator<<(std::ostream& ostr, const std::vector<T>& v)
{
// output comma delimited vector elements ...

typename std::vector<T>::const_iterator end = v.end();
for (typename std::vector<T>::const_iterator it = v.begin(); it !=


end; ++it) {
ostr << *it;
if (it + 1 != end) ostr << ", ";
}
return ostr;
}

namespace formatter {
template <class T>
class bracketed {
public:
bracketed(const T& t) : value(t) {}
const T& value;
private:
// not implemented ...
bracketed<T>& operator=(const bracketed<T>&);
};

template <class T>
std::ostream& operator>>(std::ostream& ostr, const bracketed<T>& v)
{
// enclose value in brackets ...
return ostr << '[' << v.value << ']';
}
}

int main()
{
using formatter::bracketed;

// more complicated example ...
std::vector<int> v;
v.push_back(2);
v.push_back(1);
v.push_back(0);
v.push_back(1);
v.push_back(4);
std::cout >> bracketed<std::vector<int> >(v) << std::endl;
}

In strict mode, with -tused, Compile succeeded (but remember, the
Comeau online compiler does not link).


PS. I think, these changes will not help with VC8, AFAIK it does not
support two -phase name lookup.

Pete Becker

unread,
Aug 23, 2006, 9:33:57 AM8/23/06
to
Jack Klein wrote:

> On 21 Aug 2006 20:33:28 -0400, Sam Stump
> <sMaUmDuDeYl...@verizon.net> wrote in comp.lang.c++.moderated:
>
>
>>The code below does not compile with VC8. The error is:
>>
>>sample.cpp(36) : error C2679: binary '<<' : no operator found which takes
>>a right-hand operand of type 'const std::vector<_Ty>' (or there is no
>>acceptable conversion)
>> with
>> [
>> _Ty=int
>> ]
>>
>>but it is clearly there. Is this conformant behavior or a bug?
>
>
> [snip]
>
> Almost certainly not the problem you are questioning, but your program
> is ill-formed and has undefined behavior. Your code is not allowed to
> define identifiers with a leading underscore followed by an upper case
> latter, or containing two consecutive underscores anywhere within
> them.
>

That _Ty is in the library implementation, not the user's code. It shows
up in the error messages to explain what type the template's formal
argument was bound to.

0 new messages