Boost logo

Boost :

Subject: Re: [boost] Provisional Boost.Generic and Boost.Auto_Function (concepts without concepts)
From: Matt Calabrese (rivorus_at_[hidden])
Date: 2010-12-14 06:30:39


On Tue, Dec 14, 2010 at 2:35 AM, Dean Michael Berris <mikhailberis_at_[hidden]
> wrote:

> Interesting! So which compilers are you using to test your
> implementation? Is this with MSVC or GCC?
>

GCC only at the moment.

I don't see an obvious problem here in terms of ODR here because you
> are using a template -- which by definition still gets instantiated
> anyway across multiple translation units, and is not required to have
> a single definition anyway.

It technically still is required to have one definition. In particular, see
3.2 p5 with respect to function template definitions in multiple translation
units:

 "each definition of D shall consist of the same sequence of tokens; and
— in each definition of D, corresponding names, looked up according to 3.4,
shall refer to an entity defined
within the definition of D, or shall refer to the same entity, after overload
resolution (13.3) and after
matching of partial template specialization (14.8.3), except that a name can
refer to a const object
with internal or no linkage if the object has the same literal type in all
definitions of D, and the object
is initialized with a constant expression (5.19), and the value (but not the
address) of the object is
used, and the object has the same value in all definitions of D; an"

Since the tag type may be different in different translation units as it is
dependent on which concept maps have been included and even in which order,
this should technically violate ODR.

Anyway, it's been a long time since I posted this thread and I've figured
out a way around the ODR violation -- instead of it implicitly passing the
tag type, it instead fully figures out the concept for which there is a
corresponding overload. This is fine since the concept definitions are all
the same regardless of the translation unit, unlike the tag type. The
conclusion I've come to is that any use of the tag type always needs to be
in an unevaluated context and the result should always leave no direct
"remnant" of the tag type (if that makes sense). This is rule of thumb I've
been following since then.

Note that your concept map is computed at "compile-time" right, and
> should be in a globally accessible scope -- i.e. a template
> specialization or a template class in a namespace -- right? Unless
> you're able to create a concept map at runtime or call the foo
> function outside of a function body, then I don't see how adding a new
> concept_map might be an issue for ODR.
>

It's not the concept_map itself that causes the ODR violation, it's the
implicitly created "tag type". The way the tag type works is each time a
concept map is written, it adds a function to an overload set and defines
its own return type based on previous overloads. That return type assembles
a compile-time type list of all concepts currently modeled by reaching into
the return type from the previous overload set and creating a new type list
that is the same but with the new concept added to the list. The idea is we
always have an updated type list of every single concept that is modeled by
the type.

>From that type list, I internally create the tag type, which virtually
inherits from each concept in that list. That tag type is then used under
the hood for tag dispatching when the user writes Boost.AutoFunction
overloads. The issue is, for instance, if one translation unit doesn't
include all of the same concept maps, or even if they are included in a
different order, that tag type is technically different, since the type
list, and therefore its bases, may be different or appear in a different
order. I believe this technically violates ODR because of how the tag type
is (or rather was) used by the library.

But, I believe that's all moot anyway, as, as I said, I no longer use that
approach. I now fully calculate the exact information needed to figure out
which overload should be picked and the result of the decltype should always
be exactly the same, regardless of the translation unit. All uses of the tag
type are contained entirely in decltype and no evidence of its use appears
in the resultant type, which I believe skirts the issue. It's quarantined.

> In which case you will get around that by marking
> foo<...> as an inline function, thus allowing multiple definitions
> across translation units be acceptable.
>

Again, I believe that would technically violate ODR even though the problem
would rarely be diagnosed. I'm trying to be very pedantic here, I don't want
to do something nonstandard if at all possible, even if it "works".

-- 
-Matt Calabrese

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