Re: MSVC++ 2005 Express Ed. build error when mixing boost lexical_cast
and shared_ptr
* hsmit.home@gmail.com:
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.
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";
}
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;
}
//--------------------------------------------------------------
int main (int argc, char ** argv) {
std::vector<std::string> vecstr1;
vecstr1.push_back("hi");
vecstr1.push_back("there");
std::string str = boost::lexical_cast<std::string>(vecstr1);
std::cout << str << std::endl;
return 0;
}
This compiles quite nicely and even spits out the correct output.
This version seems to use just ordinary lookup, not argument-dependent
lookup (ADL).
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
[shared_ptr.hpp] brings into play
template<class E, class T, class Y>
std::basic_ostream<E, T>& operator<<(
std::basic_ostream<E, T> & os, shared_ptr<Y> const & p
)
{
os << p.get();
return os;
}
in namespace boost.
I don't know why it's critical that it's in namespace boost (possibly
because the stream used in lexical cast is of a class defined in
namespace boost, engaging ADL in boost), but anyway, with this
definition in boost you get the above error, and with same definition in
global namespace it compiles OK. So it looks like it makes the
operator<< call in lexical_cast ambigious, via ADL. Which is difficult
to understand because SFINAE should throw it out of consideration?
But even though I can't give you exact answer (is there some language
lawyer present?) I think you get the general drift.
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????
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;
}
//--------------------------------------------------------------
int main (int argc, char ** argv) {
stringvector vecstr1; // replaced std::vector<T> with stringvector
vecstr1.push_back("hi");
vecstr1.push_back("there");
std::string str = boost::lexical_cast<std::string>(vecstr1);
std::cout << str << std::endl;
return 0;
}
Here ADL kicks in. Class defined in global namespace, lookup finds
operator>> in global namespace. Try with all in namespace trallala and
that works OK too, same reason.
This code compiles, but inheriting from an STL container is not my
idea...of a good idea...
Bah, if it works it works.
However, if you don't like it, you can (A) use containment instead of
inheritance, or (B) you can ignore the standard's silly restrictions and
simply place your operator<< in namespace std, making ADL work for you
instead of against you.
So what's going on here?
See above.
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?
See above.
2) How does inheriting from the std::vector class solve this problem?
See above.
Cheers, & hth.,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?