
"Robert Ramey" <ramey@rrsd.com> writes:
David Abrahams wrote:
The best thing you could do, IMO, is write a recommendation that works on conforming compilers, e.g.
Overload serialize in the namespace of your class.
Oh, that's news to me. I thought that would work only in compilers that implemented ADL.
I have to say, Robert, I am completely baffled at your last two replies. If I didn't know better, I'd say you were just playing head games with me. I said "conforming compilers." ADL is a part of the standard. Any compiler not implementing it is nonconforming. But surely you already knew that?
I understood from previous postings that this would entail building a set a macros which addressed the varying aspect of conformity.
The macro and usage pattern I suggested was there to address the nonconforming compilers: the ones that don't implement ADL, and don't implement 2-phase name lookup. I don't believe there's a compiler that implements 2-phase name lookup but doesn't implement ADL; that would be the only case my second suggestion wouldn't cover.
In 1.32 I had #if ... in order to place stl serializations in either the stl namespace or the boost::serialization namespace depending on whether the compiler supported ADL and two-phase lookup or neither of these things.
I can't see how putting overloads in std:: could be of any use to your library on compilers that don't support ADL, so I assume you put them in std:: on conforming compilers and put them in boost::serialization for the ones that don't conform. Putting new definitions in namespace std invokes undefined behavior. So it sounds like, depending on the compiler, you either have a broken compiler (no ADL) or a broken library (undefined behavior). That is a no-win approach. How to solve this problem is not a mystery. We just had a long thread about it entitled "[range] How to extend Boost.Range?" Have you completely missed it? I am getting frustrated here because it seems to me that you haven't done your homework, yet, after asking me to propose solutions, you resist and call them ugly.
That was the only way I could get everything to compile on all platforms.
It seems to me from what you've been saying that your approach to solving the serialize( ... ) dispatching/customization problem here has been to try different configurations of the code until you could get it to pass select tests on certain platforms, without regard for standard conformance and theoretical portability. That's a well-known way to end up with code that doesn't work portably or in configurations you haven't tried (for example, hmm, let me think... when the order of headers changes).
Then generated the requirement to address the issue in the documentation with a table on what the user should use. That's what I call ugly.
Huh? I didn't propose a table. And, IMO there's nothing particularly inelegant about using a table in documentation; there's well-established precedent for it in the standard and Boost. Certainly documenting what the user should do is a must. So I don't see what you're unhappy about. If you don't like having to tell users to do something special on nonconforming compilers, well, the answer is to either find a clean idiom that works everywhere (for this particular problem, many have tried -- I don't believe such an idiom exists) or stop supporting those broken compilers.
FWIW - I'm not sure if the example you site would ever come up in practice - it certainly hasn't yet. If I understand this correctly, the problem would occur if someone writes somethng like:
my_class.hpp
class my_class ...
template<class Archive, my_class> void serialize(Archive &ar, my_class & t, cont unsigned int version); // declaration only
my_app.cpp
main(... { my_class mc; ... ar & mc; }
template<class Archive, my_class> void serialize(Archive &ar, my_class & t, cont unsigned int version); // definition only
No. The problem has nothing to do with the location of definitions. You can keep all definitions and declarations together, and the problem still occurs. // <boost/serialization/some_file.hpp> namespace boost { namespace serialization { // Something in the serialization library template <class T> int call_serialize(T const& x) { serialize(x); return 0; } }} // "user_header.hpp" namespace me { class X {}; } // User overloads in boost::serialization, per your recommendation namespace boost { namespace serialization { void serialize(me::X) { // definition } }} // "user.cpp" int y = boost::serialization::call_serialize(me::X()); Read the passage of the standard I quoted to you, and look carefully at the example above. Do your homework.
I'm not absolutly sure that this is the only scenario which would create problem and that's why I wanted more time to consider it.
If this is the only way the two-phase problem could manifest itself, I would guess that in practice it would never be an issue. I don't see users doing this. This was what I was getting at when I asked why the problem hasn't appeared upto now. Of course I don't really know whether this is because so many compilers fail to implement two-phase lookup.
Jeez Louise, Robert! This is a well-known problem. It occurs in practice. There's nothing unique about the serialization library in this respect. It has a customization point (called "serialize") that is used from the library without qualification. You expect to find it via Argument Dependent Lookup, **whose job is to look for overloads in the associated namespace of the arguments**. If the overload is in boost::serialization and no arguments are associated with that namespace, it won't be found via ADL. That leaves ordinary lookup, which only looks backwards from the templates point-of-definition. Could that _possibly_ be any clearer? Lots of generic libraries have a similar dispatching issue to address, e.g. Boost.Range. There's a nice, free online compiler againist which you can test your 2-phase problems. I've quoted the standard chapter and verse. I've given you simple example programs that demonstrate the problem. I don't know what more I can do... do I need to build a program that actually uses the serialization library before you'll believe me?!
b) I'm going to remove the class declaration and function implementation from the Archive Concept part of the document.
Are you planning to replace it with anything? It would be pretty silly to have a section called Archive Concept with no concept description.
I meant to leave in the text below the "class" schema. Before I started I reviewed again the SGI documents and concluded that that text could be fit into the SGI form for concepts. I'm using http://www.sgi.com/tech/stl/Container.html as a "typical example". This isn't hard - its basically a question of reformatting. I hope that will be satisfactory.
Me too. That will depend on your execution :) -- Dave Abrahams Boost Consulting www.boost-consulting.com