
On Tue, Dec 14, 2010 at 2:35 AM, Dean Michael Berris <mikhailberis@gmail.com
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.
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
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. 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