Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2005-09-06 13:26:27


"Robert Ramey" <ramey_at_[hidden]> writes:

> .>> 4. The documentation says that you can write your freestanding
>>>> serialize() function in namespace boost::serialization, with the
>>>> strong implication that it will work even on compilers that
>>>> support ADL. But it won't work unless boost::serialization is an
>>>> associated namespace of one of the arguments, as demonstrated by
>>>> the following program:
>>>>
>>>>
>>>> namespace me
>>>> {
>>>> class X {};
>>>> }
>>>>
>>>> namespace boost { namespace serialization
>>>> {
>>>>
>>>> template <class T>
>>>> int call_serialize(T const& x)
>>>> {
>>>> serialize(x);
>>>> return 0;
>>>> }
>>>>
>>>> void serialize(me::X);
>>>>
>>>> }}
>>>>
>>>> int y = boost::serialization::call_serialize(me::X());
>>
>> In case it wasn't 100% obvious, the above fails to compile on a
>> conforming compiler.
>
> Well it wasn't obvious to me. Its still not. It just compiled on my comeau
> 4.3 without error.
>
> I always thought that compiler was conforming. Oh well.

On Windows? That's normally in "microsoft bug emulation mode." Try
http://www.comeaucomputing.com/tryitout (I did!)

I hate having to go crawling through the standard just to find this
stuff, but for you, because I like you, kid, I make a special
exception:

  14.6.4 Dependent name resolution [temp.dep.res]

    In resolving dependent names, names from the following sources are
    considered:

    â€” Declarations that are visible at the point of definition of the
      template.

    â€” Declarations from namespaces associated with the types of the
      function arguments both from the instantiation context
      (14.6.4.1) and from the definition context.

Unless one of the arguments has boost::serialization as an associated
namespace, only the first bullet point applies in this case. It means
that any overloads provided by the user after the call_serialize
function definition has been seen will not be considered for overload
resolution.

> Maybe no one has every had an issue with this as it is customary and
> natural to declare and/or define the template
>
> template<class Archive>
> void serialize(Archive &ar, me::X, const unsigned int version){
> ...
> }
>
> in the same header where X itself is declared and/or defined.

That's irrelevant to the problem, actually.

> Also the body of the serialize function typically will refer only to
> member data and functions.

So? The problem happens during name lookup. If the user's serialize
overload is never considered, it doesn't matter what gets put in its
implementation.

> But the truth is I would have to delve into this a lot deeper to see
> what's going on here.

Well, you'd better. The documentation as of now is not adequate to
know how to write an archive that works with the serialization library.

>>>> As far as I can tell, there's no requirement that any of the
>>>> arguments to serialize have boost::serialization as an associated
>>>> namespace.
>>>
>>> There isn't. And I don't think it's necessary. serialize(me::X) is
>>> only called from within the namespace boost::serialization never
>>> from anywhere out side this namespace. Hence, the serialize
>>> function is found according to the rules of ordinary lookup.
>>
>> No, not in the example above it isn't, because serialize follows the
>> definition of call_serialize.
>
> As above its not clear to me that anyone ever does this.

??

  #include <boost/serialization/header-containing-call_serialize.hpp>
  #include "mytype-and-its-serialize-function.hpp"

is all it takes.

>> The set of candidates that can be found by ordinary lookup is fixed
>> at the template's point of definition.
>
>> You have introduced yet another header order dependency here. You
>> don't need to experience the wailing and gnashing of teeth associated
>> with that problem again, do you?
>
> I'm getting used to it.

Please, don't get used to it! If your tolerance for it goes up any
further nobody will be able to convince you to fix anything! ;-)

> Actually this would be much worse than the one before. In my other
> infamous case, at least the compiler threw and #error when the rule
> was violated. With two-phase lookup, the compiler silently changes
> the program semantics when header order is changed.

It's not two-phase lookup that's the culprit, it's incorrect
instructions about how to customize the serialize() functionality.

>>> If one's compiler supports ADL, then he can use a free function in
>>> namespaces associated with the type being serialized. But it's
>>> not a requirement
>>
>> I beg to differ. And the docs make it sound as though putting the
>> functions in boost::serialization is the more portable of the two
>> options.
>
> Hmm - if one puts in the boost::serialization namespace it works
> except mayb in cases such as that above.

??
It fails unless one of the arguments to serialize has
boost::serialization as an associated namespace. That's

> Its not clear to me that that is not a contived example which never
                           ^^^^
                           what is "that?"
> happens in practice.

> If one puts in the namespace of the class being serialized - it
> depends upon ADL to function. So my view is that putting it into
> boost::serialization is more portable.

Even if that were true in practice, you can't recommend a practice
that doesn't work on a conforming compiler as the more portable of the
two, at least not without a big caveat that it relies on nonportable
techniques... can you?!

> In reality I suspect its not such an issue these days as most
> compilers seem to support ADL.
>
>>> I concede I've struggled with two-phase lookup and ADL so I'm
>>> willing to be shown to be wrong about this.
>
>> The example above demonstrates.
>
> Hmm - I'm not convinced yet.

The online compiler demonstrates.

>> Yes, I understand what the intent is. Actually, there is precedent
>> for what you're trying to do, sorta. The Indiana proposal for
>> concepts in C++0x
>> (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1849.pdf)
>> uses something called a "pseudo-signature" that looks very much like
>> what you've written. However, there are special rules for reading and
>> understanding pseudo-signatures. One way to make your specification
>> formally complete would be to make sure that, when expressed according
>> to the rules in that proposal, it says what you mean it to say. Then
>> you can reference the proposal in the docs in case someone wants to
>> understand the requirements on a formal level.
>
> Well, I didn't know about this. But your explanation doesn't make sound
> very easy to understand or use.

Very well, then, if you don't like that, use the "traditional" table
of valid expressions, etc.

>>>> What about the names of function and member template parameters?
>
> What about about them? What is the question here?

Do I have to use the same names as you do in your example?

>>>> I know the answer to that one, but a novice might not.
>
> What is the answer?

No.

>> Maybe. It's certainly not complete enough for someone like me to be
>> sure of what it really means.

<referring to the SGI STL docs>

>> :) I'm using it on some slides now and discovering just how many
>> holes, anachronisms, and inaccuracies there are in it. Still, the
>> basic approach is a good one.
>
>> I don't actually think Bill Kempf's format results in particularly
>> good docs. I used that approach for Boost.Python's reference and now
>> I wish I hadn't. I think the Parameter library (admittedly much
>> smaller) is much better.
>
> Then someone should update those pages.

Or replace them.

> I've strived to do things in the "boost" way to maximize the mental
> leverage to be gained from using an established pattern. If we
> should use them we should have another model.

Feel free to propose one.

> BTW, updating these pages ain't going to be that easy.
> Traditionally, C/C++ programs were fairly easy to describe with an
> interface for each class along with notes regarding implementation
> semantics. Now with both class and function templates the old
> patterns are not enough. I look forward to seeing this improved.

Me too. <taps foot expectantly>

> Another great idea would be to tie concept checking into the
> "formal" template documentation so that the code checks the
> documentation. A way too ambitious idea but fun to consider.

Already in the pipeline, believe it or not.

>>> As I said, I see this implementation section as a means to
>>> fullfilling the basic requirement not as new requirements.
>>
>> You said that? Where?
>
> Reference/Archive Class Reference/Implementation states in its opening
> paragraph:
>
> The Archive concept specifies the functions that a class must
> implement to in order to be used to serialize Serializable
> types. The library implements a family of archives appropriate for
> different purposes. This section describes how they have been
> implemented and how one can implement his own archive class.
>
> That seems pretty clear to me that the are archives included model he
> Archive concept. It would be easy to add that sentence

Sorry, I can't understand anything you're trying to tell me in the
whole quoted section above, so I don't know if it would help.

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk