Concept based overloading and the ODR

AMDG I'm looking at two recent posts: http://comments.gmane.org/gmane.comp.lib.boost.devel/177370 http://comments.gmane.org/gmane.comp.lib.boost.user/37476 Either of these is fine by itself, but putting them both together makes it very easy to cause silent ODR problems. For example in translation unit a.cpp we #include "boost/tuple/tuple_io.hpp" and translation unit b.cpp we forget. Then, along comes boost::any which detects operator<< in translation unit a.cpp, but uses its default in translation unit b.cpp. Ka-Boom. This is not a huge problem at the moment, because it's quite difficult to make the detection bullet-proof, but I'm very concerned because C++0x concepts are supposed to make such overloading easy. In Christ, Steven Watanabe

on Thu Jul 10 2008, Steven Watanabe <watanabesj-AT-gmail.com> wrote:
AMDG
I'm looking at two recent posts: http://comments.gmane.org/gmane.comp.lib.boost.devel/177370 http://comments.gmane.org/gmane.comp.lib.boost.user/37476
Either of these is fine by itself, but putting them both together makes it very easy to cause silent ODR problems.
Heh, I just noticed the same issue.
For example in translation unit a.cpp we #include "boost/tuple/tuple_io.hpp" and translation unit b.cpp we forget. Then, along comes boost::any which detects operator<< in translation unit a.cpp, but uses its default in translation unit b.cpp. Ka-Boom.
This is not a huge problem at the moment, because it's quite difficult to make the detection bullet-proof,
I don't think that accurately characterizes the issue. I think few compilers do anything to detect ODR violations. However, link-time stripping of common template instantiations (or link-time instantiation) seems likely to cause only a single behavior in both TUs where two behaviors may have been intended.
but I'm very concerned because C++0x concepts are supposed to make such overloading easy.
I'm not sure I see the relationship to C++0x concepts. Care to say more? -- Dave Abrahams BoostPro Computing http://www.boostpro.com

AMDG David Abrahams wrote:
I don't think that accurately characterizes the issue. I think few compilers do anything to detect ODR violations. However, link-time stripping of common template instantiations (or link-time instantiation) seems likely to cause only a single behavior in both TUs where two behaviors may have been intended.
I'm sorry I wasn't clear. What I meant was that it's quite difficult to implement a test to see whether a given overload is present, so it isn't used very often. The real danger of course, is that when multiple functions depend on the presence of absence of an overload, the linker can select definitions of two functions which are incompatible.
but I'm very concerned because C++0x concepts are supposed to make such overloading easy.
I'm not sure I see the relationship to C++0x concepts. Care to say more?
I think that templates which are vulnerable to this kind of nastiness are likely to be much more common with C++0x concepts. That's all. I'm thinking that the most reliable way to deal with this is to /always/ provide forward declarations of functions that should be found by ADL, even if they are defined in a separate header. In Christ, Steven Watanabe

on Fri Jul 11 2008, Steven Watanabe <watanabesj-AT-gmail.com> wrote:
I'm thinking that the most reliable way to deal with this is to /always/ provide forward declarations of functions that should be found by ADL, even if they are defined in a separate header.
That's a good answer. However, note that the first link you posted was from someone who wouldn't want such a declaration to be seen. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

AMDG David Abrahams wrote:
on Fri Jul 11 2008, Steven Watanabe <watanabesj-AT-gmail.com> wrote:
I'm thinking that the most reliable way to deal with this is to /always/ provide forward declarations of functions that should be found by ADL, even if they are defined in a separate header.
That's a good answer. However, note that the first link you posted was from someone who wouldn't want such a declaration to be seen.
I don't think that #includeing vs. not #including a header is a good way to restrict the declarations present. Code that relies on a particular header *not* having been #included is fundamentally broken, IMO. The only safe way to allow replacement of a library function that I know of is to use a macro, since this can be set globally. In Christ, Steven Watanabe

on Fri Jul 11 2008, Steven Watanabe <watanabesj-AT-gmail.com> wrote:
AMDG
David Abrahams wrote:
on Fri Jul 11 2008, Steven Watanabe <watanabesj-AT-gmail.com> wrote:
I'm thinking that the most reliable way to deal with this is to /always/ provide forward declarations of functions that should be found by ADL, even if they are defined in a separate header.
That's a good answer. However, note that the first link you posted was from someone who wouldn't want such a declaration to be seen.
I don't think that #includeing vs. not #including a header is a good way to restrict the declarations present. Code that relies on a particular header *not* having been #included is fundamentally broken, IMO.
I fully agree. My point was that he's got a problem that we're not solving by simply insisting on ODR-friendly practices.
The only safe way to allow replacement of a library function that I know of is to use a macro, since this can be set globally.
Many people think macros are too ODR-prone also. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

AMDG David Abrahams wrote:
I fully agree. My point was that he's got a problem that we're not solving by simply insisting on ODR-friendly practices.
The only safe way to allow replacement of a library function that I know of is to use a macro, since this can be set globally.
Many people think macros are too ODR-prone also.
What other ways are there to solve it? I realize that macros are still dangerous but they are better than any alternative that I know--other than only allowing customization through specializations that involve at least one user defined type. Is there any known way of automatically triggering a link error if macros are defined differently in different translation units? I can think of a manual way: a.cpp: void BOOST_PP_CAT(a_cpp_compatibility, OPTIONS_ENCODED_AS_IDENTIFIER)() {} b.cpp static void test_a_cpp_compatibility() { BOOST_PP_CAT(a_cpp_compatibility, OPTIONS_ENCODED_AS_IDENTIFIER)(); } In Christ, Steven Watanabe
participants (2)
-
David Abrahams
-
Steven Watanabe