Re: MSVC++ 2005 Express Ed. build error when mixing boost
lexical_cast and shared_ptr
On Nov 19, 8:14 pm, hsmit.h...@gmail.com wrote:
I came across a strange error and it's really been bugging me. Maybe
someone else has come across this and any insight would be
appreciated.
What I'm trying to accomplish is using boost::lexical_cast to cast a
vector of strings to a string.
I don't think it's possible, at least not with a standards
conformant compiler, which does dependent name lookup correctly.
(Strangely enough, it does compile with g++, although I can't
figure out how.) Unless I've misunderstood something
completely, boost::lexical_cast uses << and >> on the
instantiation types. The expression is dependent, so =A714.6.4
should apply.
I've found this to be the case in other constructs with g++, so
something else is occuring which I don't understand.
The compiler I'm using is MSVC++ 2005 Express Edition. The
gc++ compiler does not have the same complaint, this is
strictly a MSVC++ 2005 issue. I don't think it matters, but
I'm running on a WinXP 32 bit machine. I'm also using boost
v1.34.0.
Here's the code.
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <vector>
#include <string>
//--------------------------------------------------------------
template<class T>
std::ostream & operator<<(std::ostream& s, const std::vector<T> & d) {
typedef typename std::vector<T>::const_iterator iter;
iter it;
for (it = d.begin() ; it != d.end() ; ++it) {
s << *it;
s << "\n";
Why not just:
s << *it << '\n' ;
?
Or even replacing the entire loop by:
std::copy( d.begin(), d.end(), std::ostream_iterator( s,
"\n" ) ) ;
}
return s;}
Normally, this function should not be found during dependent
name lookup, at least as I understand the standard.
//--------------------------------------------------------------
template<class T>
std::istream & operator>>(std::istream& s, std::vector<T> & d) {
while (!s.eof()) {
char buf[500];
Why not std::string?
s.getline(buf, sizeof(buf));
You'd best check the success of the getline before using the
value read.
d.push_back(buf);
}
The standard idiom here is:
std::string line ;
while ( std::getline( s, line ) ) {
d.push_back( line ) ;
}
return s;
}
This compiles quite nicely and even spits out the correct output.
Which is what I don't understand. As far as I can see, it
shouldn't compile.
Now for the problem:
If I change the include #includes at the top to:
#include <boost/lexical_cast.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <vector>
#include <string>
I get the following compilation error (only the last few lines are
provided for clarity):
lexical_cast.hpp(150) : while compiling class template member function
'bool boost::detail::lexical_stream<Target,Source>::operator <<(const
Source &)'
with
[
Target=std::string,
Source=NewSource
]
lexical_cast.hpp(219) : see reference to class template instantiation
'boost::detail::lexical_stream<Target,Source>' being compiled
with
[
Target=std::string,
Source=NewSource
]
main.cpp(38) : see reference to function template instantiation
'Target boost::lexical_cast<std::string,std::vector<_Ty>>(const Source
&)' being compiled
with
[
Target=std::string,
_Ty=std::string,
Source=std::vector<std::string>
]
lexical_cast.hpp(151) : error C2228: left of '.fail' must have class/
struct/union
Now, for a really stupid solution:
#include <boost/lexical_cast.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <vector>
#include <string>
//--------------------------------------------------------------
// inheriting from an STL container - asking for trouble!
// But it does solve the compilation problem. WHY????
Because you then use a class defined in the global namespace.
Which means that the global namespace is drawn into ADL.
class stringvector : public std::vector<std::string> {
};
//--------------------------------------------------------------
template<class T>
std::ostream & operator<<(std::ostream& s, const std::vector<T> & d) {
typedef typename std::vector<T>::const_iterator iter;
iter it;
for (it = d.begin() ; it != d.end() ; ++it) {
s << *it;
s << "\n";
}
return s;}
//--------------------------------------------------------------
template<class T>
std::istream & operator>>(std::istream& s, std::vector<T> & d) {
while (!s.eof()) {
char buf[500];
s.getline(buf, sizeof(buf));
d.push_back(buf);
}
return s;
}
This is tricky, of course. But basically, as some point, you
have a << or a >> with a ::stringvector as an argument. So ::
is pulled in, and the compiler finds the above functions.
This code compiles, but inheriting from an STL container is not my
idea...of a good idea...
So what's going on here?
There are basically 2 questions I have:
1) why does the boost/shared_ptr.hpp inclusion effect a
boost::lexical_cast<std::string, std::vector> declaration?
That I don't know. IMHO, without the inheritance, the code
should never compile.
2) How does inheriting from the std::vector class solve this problem?
Because you're now using a class declared in the global
namespace.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34