Subject: Re: [boost] Provisional Boost.Generic and Boost.Auto_Function (concepts without concepts)
From: Dean Michael Berris (mikhailberis_at_[hidden])
Date: 2010-12-14 07:02:40
On Tue, Dec 14, 2010 at 7:30 PM, Matt Calabrese <rivorus_at_[hidden]> wrote:
> On Tue, Dec 14, 2010 at 2:35 AM, Dean Michael Berris <mikhailberis_at_[hidden]
>> Interesting! So which compilers are you using to test your
>> implementation? Is this with MSVC or GCC?
> GCC only at the moment.
Cool. Interesting indeed. This is GCC 4.5 in --std=c++0x mode right?
>> 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
> Â "each deï¬nition of D shall consist of the same sequence of tokens; and
> â in each deï¬nition of D, corresponding names, looked up according to 3.4,
> shall refer to an entity deï¬ned
> within the deï¬nition 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
> deï¬nitions 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 deï¬nitions 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.
Yes, but then your instantiation of the template would be different,
since the stuff in the decltype changes -- so technically they're not
the same instantiations anymore, because technically they're different
types. Am I understanding that wrong? Also, I'm assuming this is the
latest draft of the standard post-Batavia, right?
> 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".
Yeah, but... I thought 'inline' was meant to be the "way out" to the
"ODR" problem with templates? :)
-- Dean Michael Berris deanberris.com
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk