
On 03/05/11 21:28, Matthew Chambers wrote: <snip>
I use an optional header that defines lexical_cast string->numeric specializations using strto[ld]. Is this at risk for ODR violations? I use it widely but I'm not at all careful about making sure it's included everywhere. Yet I haven't had any ODR violations on GCC or MSVC. Unless that's pure luck, I'd like to know how the optional specializations are ODR violations.
The thing about ODR violations is that most of the time your program will work fine despite containing them, and it's practically impossible for a compiler to detect them (I think the very latest versions of gcc make some attempt, but not much). So, you might easily have them and not know. On the one hand, the fact that they rarely break the program means that we might be somewhat blasé and not worry about them, but on the other hand I certainly think Boost should not promote deliberate violations of the standard, and I suspect these things might lead to more problems with whole-program optimization. If you would like a concrete example, here's one. Suppose we're implementing a C++ version of the Python repr functionality (called, perhaps foolishly, "print", here). We have a default implementation which simply prints out the typeid and address of the object, and it can be specialised for specific types where appropriate. I have written two functions, f() and g(), both of which print out the integer 0, but g does it in the presence of a specialization, and f does not. (I've had to use "__attribute__((noinline))" in this code to make the badness obvious, but of course the compiler is always at liberty to not inline the function, so the badness was always there) ===== print.hpp #include <cstdio> #include <typeinfo> template<typename T> struct print_helper { void operator()(T const& t) { std::printf("<%s at %p>\n", typeid(T).name(), &t); } }; template<typename T> __attribute__((noinline)) void print(T const& t) { print_helper<T>()(t); } void f(); void g(); ===== f.cpp #include "print.hpp" void f() { print(0); } ===== g.cpp #include "print.hpp" template<> struct print_helper<int> { void operator()(int const& t) { std::printf("int(%d)\n", t); } }; void g() { print(0); } ===== main.cpp #include "print.hpp" int main() { f(); g(); return 0; } There is an ODR violation in this program because there are two definitions of print<int>, and they violate N3092 [basic.def.odr] p7 point 2, because the name "print_helper<T>" refers to different entities in the two definitions. This ODR violation does indeed lead to undefined behaviour; observe what happens when I compile and run this program: $ g++ -o odr main.cpp f.cpp g.cpp $ ./odr <i at 0x7fff0d49ef8c> <i at 0x7fff0d49ef8c> $ g++ -o odr main.cpp g.cpp f.cpp $ ./odr int(0) int(0) It does different things according the the order in which I pass the source files on the command line. This is because the two (different) definitions of print<int> are being merged into one. There may or may not be a second ODR violation because of the two different definitions of print_helper<int>. My standard-ese is insufficient to figure out whether this is a violation or not. But even this first problem could clearly arise if e.g. library A which uses Boost.Convert in a template function to perform a conversion which is specialised by library B which depends on library A. This is very difficult to detect and avoid. John Bytheway