[Serialization] Non-standard extensions used.

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

Stephen Hewitt <shewitt.au <at> gmail.com> writes:
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.
I think you have to change it a little to make it legal:
The "make_nvp" function looks like as follows: [CODE] nvp<T> make_nvp(const char * name, T & t){ return nvp<T>(name, t); } [/CODE]
If the return type is "const vnp<T>" it should work. I'm wondering why the orginal code compiles on other compilers. best regards Thorsten

On Aug 9, 2006, at 10:17 PM, Thorsten Ottosen wrote:
Stephen Hewitt <shewitt.au <at> gmail.com> writes:
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.
I think you have to change it a little to make it legal:
The "make_nvp" function looks like as follows: [CODE] nvp<T> make_nvp(const char * name, T & t){ return nvp<T>(name, t); } [/CODE]
If the return type is "const vnp<T>" it should work.
I'm wondering why the orginal code compiles on other compilers.
Actually the code in the CVS is: template<class T> inline #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING const #endif nvp<T> make_nvp(const char * name, T & t){ return nvp<T>(name, t); } The const is omitted only on some nonconforming compilers such as MSVC 6. Matthias
participants (3)
-
Matthias Troyer
-
Stephen Hewitt
-
Thorsten Ottosen