I have a potential ODR violation happening in a large code base. It's a class template that switches behavior based on a #ifdef in different libraries, but the conflicting libs are likely using different instantiations of the template. As a simplified example:
// foo.h
#ifdef USE_DOUBLE
template <typename T>
struct foo { T* value; double x; };
#else
template <typename T>
struct foo { T* value; };
#endif
struct c;
// a_lib.cpp
#include "foo.h"
struct a { foo<a> m_a; };
struct a_helper { foo<c> m_c; };
// b_lib.cpp
#define USE_DOUBLE
struct b { foo<b> b; };
struct b_helper { foo<c> m_c; };
foo<a> and foo<b> don't have an ODR violation, correct?foo<c> brought in by a_helper and b_helper just got incredibly sketchy, correct?The catch is that I have this in a huge project. Also, it's likely (but not certain) that I have only the equivalent of non-overlapping a and b, and not the problematic a_helper and b_helper. However, I can't really be sure.
I'm wondering if I can dodge this problem by changing foo to an alias template:
template <typename T>
struct foo_double_impl { T* value; double x; };
template <typename T>
struct foo_impl { T* value; };
#ifdef USE_DOUBLE
template <typename T>
using foo = foo_double_impl<T>;
#else
template <typename T>
using foo = foo_impl<T>;
#endif
The ODR is specified rather lengthily in the standard that boils down to saying you must
To sum up, they really really have to be identical in all possible manners.
In all your scenarios, foo violates ODR by having a differing sequence of tokens.
The best fix without altering the libraries are inline namespaces
#ifdef USE_DOUBLE
inline
#endif
namespace D {
    template <typename T>
    struct foo { T* value; double x; };
} 
#ifndef USE_DOUBLE
inline
#endif
namespace ND {
    template <typename T>
    struct foo { T* value; };
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With