[Serialization] Non-standard extensions used.

The following is a dead simple example of using Boost.Serialization using an XML output archive which follows the patterns laid down in examples: /* \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ */ #include <iostream> #include <boost/archive/xml_oarchive.hpp> #include <boost/serialization/nvp.hpp> // Warning level 4. #pragma warning(push, 4) #pragma message("********") 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) /* \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ */ 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 Interestingly I could not get it to happen with "Microsoft Visual C++ Toolkit 2003". The warning seems valid to me. The "BOOST_SERIALIZATION_NVP" looks like this: -------------------------------------------------------------------------------------------------------------------------- #define BOOST_SERIALIZATION_NVP(name) \ boost::serialization::make_nvp(BOOST_PP_STRINGIZE(name), name) -------------------------------------------------------------------------------------------------------------------------- The "make_nvp" function looks like as follows: ------------------------------------------------------- nvp<T> make_nvp(const char * name, T & t){ return nvp<T>(name, t); } ------------------------------------------------------- "Operator<<", which is used in "main" is reproduced below: -------------------------------------------------------------------------------------- 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 ... // }; -------------------------------------------------------------------------------------- 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++!?!

My understanding of the standard is that this operation is legal but that the compiler writer has the option of using a copy operation to implement it. a) As far as I know - no compiler we've used has done this. b) nvp is a "wrapper" in that it is just a holder for the underlying values to be serialized - so making a copy of this wrapper would do no harm. This issue has provoked a lot of problematic behavior between compilers. I'm not sure whether the current situation is the result of evolution to universal functionality or just an original oversight which has never been addressed. It's interesting to consider - but not urgent as it has no practical impact on the operation of the library. Note that microsoft vc compilers of late are in the habit of emitting warning messages alledging "deprecated" or non-standard behavior where none exists. Also, some standard behavior (e.g. two-phase lookup) is not implemented by microsoft compilers. So using a microsoft C++ compiler (Or any particular compiler) as a definitive test for code conformance to the standard is ill-advised. Robert Ramey "Stephen Hewitt" <shewitt.au@gmail.com> wrote in message news:c7c622110608070558o56184437v8a57320a0510171@mail.gmail.com... The following is a dead simple example of using Boost.Serialization using an XML output archive which follows the patterns laid down in examples: /* \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ */ #include <iostream> #include <boost/archive/xml_oarchive.hpp> #include <boost/serialization/nvp.hpp> // Warning level 4. #pragma warning(push, 4) #pragma message("********") 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) /* \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ */ 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 Interestingly I could not get it to happen with "Microsoft Visual C++ Toolkit 2003". The warning seems valid to me. The "BOOST_SERIALIZATION_NVP" looks like this: -------------------------------------------------------------------------------------------------------------------------- #define BOOST_SERIALIZATION_NVP(name) \ boost::serialization::make_nvp(BOOST_PP_STRINGIZE(name), name) -------------------------------------------------------------------------------------------------------------------------- The "make_nvp" function looks like as follows: ------------------------------------------------------- nvp<T> make_nvp(const char * name, T & t){ return nvp<T>(name, t); } ------------------------------------------------------- "Operator<<", which is used in "main" is reproduced below: -------------------------------------------------------------------------------------- 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 ... // }; -------------------------------------------------------------------------------------- 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++!?! _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

I find the C++ standard a bit like reading a legal document (and I'm no lawyer) but the following is from ISO 14882: 3.10/5: "The result of calling a function that does not return a reference is an rvalue. User defined operators are functions, and whether such operators expect or yield lvalues is determined by their parameter and return types." 8.5.3/5 (extract): "Otherwise, the reference shall be a non-volatile const type (i.e., cvl shall be const)." 8.5.3/5 is a little complicated however and I've only quoted a small portion of it; some careful reading is probably in order. The behaviour you seem to be referring to when you say, "the compiler writer has the option of using a copy operation to implement it", is a sub-point of the point in my quote and thus I think it only applies if the reference is const. Again I feel I need to point out that I found this part of the standard more than a little confusing. There are a number of places in the standard which refer to the binding of non-const references to temporaries and refer to it as an error. I find further evidence for my assertion in the following links: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html - The whole purpose of this proposal is to address the fact that rvalues can not be bound to non-const references. http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1385.htm - Describes the "Forwarding Problem". Regards, Steve PS: Sorry if this is a re-post but I had a little trouble figuring out how to reply.
participants (2)
-
Robert Ramey
-
Stephen Hewitt