Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can differing alias templates resolve potential ODR violations across libraries?

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; };
  1. I'm guessing that foo<a> and foo<b> don't have an ODR violation, correct?
  2. But that the differing definitions of 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
  1. Now, instead of two differing definitions of foo, we now have a definition of foo_impl and foo_double_impl. Does this resolve the ODR violation? Or does the ODR violation persist because there are two different alias templates of foo?
like image 795
Ryan Shepherd Avatar asked Oct 28 '25 04:10

Ryan Shepherd


1 Answers

The ODR is specified rather lengthily in the standard that boils down to saying you must

  • Have exactly one definition of a non-inline function or variable
  • Have at least one definition of everything else used. The multitudes of definitions must be exactly the same, including
    • Have the same sequence of tokens
    • Have the sequence of tokens mean the same thing
    • Have all the lookup of the corresponding tokens find the same things

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; };
}
like image 164
Passer By Avatar answered Oct 30 '25 18:10

Passer By



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!