|
Boost : |
From: Stephen Hewitt (shewitt.au_at_[hidden])
Date: 2006-08-09 07:42:08
I originally posted this message in Boost-users but I think Boost-developers
is probably more suitable. It regards a non-standard extension which I think
is being used in Boost.Serialization. I have mailed the author (and
Boost-users) but he feels the construct is legal.
The following is a dead simple example of using Boost.Serialization with an
XML output archive which follows the patterns laid down in examples:
[CODE]
#include <iostream>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/nvp.hpp>
// Warning level 4.
#pragma warning(push, 4)
struct MyData
{
MyData(int val) : m_Value(val) {}
template<typename Archive>
void serialize(Archive & ar, const unsigned int)
{
ar & BOOST_SERIALIZATION_NVP(m_Value); // <-- Warning here.
}
int m_Value;
};
void main()
{
using namespace std;
MyData d(3);
boost::archive::xml_oarchive oa(cout);
oa << BOOST_SERIALIZATION_NVP(d); <-- Warning here.
}
// Warning level back to normal.
#pragma warning(pop)
[/CODE]
When compiling this code I get the following error:
"warning C4239: nonstandard extension used : 'argument' : conversion from
'struct boost::serialization::nvp<struct MyData>' to 'struct
boost::serialization::nvp<struct MyData> &'
A reference that is not to 'const' cannot be bound to a non-lvalue"
I tried MSVC 6 and "Visual C++ 2005" (which can be downloaded from here
http://msdn.microsoft.com/vstudio/express/visualC/default.aspx) and got the
same error.
Interestingly I could not get it to happen with "Microsoft Visual C++
Toolkit 2003" (perhaps I made a mistake?).
The warning seems valid to me. The "BOOST_SERIALIZATION_NVP" looks like
this:
[CODE]
#define BOOST_SERIALIZATION_NVP(name) \
boost::serialization::make_nvp(BOOST_PP_STRINGIZE(name), name)
[/CODE]
The "make_nvp" function looks like as follows:
[CODE]
nvp<T> make_nvp(const char * name, T & t){
return nvp<T>(name, t);
}
[/CODE]
"Operator<<", which is used in "main" is reproduced (in part) below:
[CODE]
template<class Archive>
class interface_oarchive
{
// ... Code removed ... //
template<class T>
Archive & operator<<(T & t){
this->This()->save_override(t, 0);
return * this->This();
}
// ... Code removed ... //
};
[/CODE]
So, to cut to the chase, "BOOST_SERIALIZATION_NVP" expands to a call to
make_nvp" which returns a temporary which is bound to a non-const reference
in "interface_oarchive::operator<<": this is not legal in standard C++
(unless I'm mistaken).
It seems that if you follow to documentation and examples the resulting code
isn't standard C++!?!
I find the C++ standard a bit like reading a legal document (and I'm no
lawyer) but the following sections from ISO 14882 seem to agree that binding
a non-const reference to a temporary is illegal: 3.10/5 & 8.5.3/5.
I find further evidence for my assertion in the following links:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html
http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1385.htm
Perhaps this issue (assuming I'm correct) seems minor but for me one of the
good things about Boost is that it strives avoid non-standards extensions
where possible. Also the longer it remains "broken" (again, assuming I'm
correct) the more chance a fix will break existing code.
I feel the simplest fix would be to make operator<< take a constant
reference. The author suggested that the problem could also be solved by
making the return value of "make_nvp" constant.
Regards,
Steve
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk