Могут ли различные шаблоны псевдонимов разрешить возможные нарушения ODR в разных библиотеках?
У меня есть потенциальное нарушение ODR, происходящее в большой базе кода. Это шаблон класса, который переключает поведение на основе #ifdef в разных библиотеках, но конфликтующие библиотеки, вероятно, используют разные экземпляры шаблона. В качестве упрощенного примера:
// 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>
а такжеfoo<b>
нет нарушения ODR, верно? - Но это разные определения
foo<c>
принесa_helper
а такжеb_helper
просто получилось невероятно схематично, верно?
Подвох в том, что у меня есть это в огромном проекте. Кроме того, вполне вероятно (но не уверен), что у меня есть только эквивалент не перекрытия a
а также b
и не проблемный a_helper
а также b_helper
, Тем не менее, я не могу быть уверен.
Мне интересно, смогу ли я избежать этой проблемы, изменив foo на шаблон псевдонима:
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
- Теперь вместо двух разных определений foo у нас теперь есть определения foo_impl и foo_double_impl. Разрешает ли это нарушение ODR? Или нарушение ODR сохраняется, потому что существует два разных псевдонима шаблона foo?
1 ответ
ODR довольно долго указан в стандарте, который сводится к тому, что вы должны
- Иметь ровно одно определение не встроенной функции или переменной
- Имейте хотя бы одно определение из всего, что используется. Множество определений должны быть точно такими же, включая
- Имеют одинаковую последовательность токенов
- Пусть последовательность токенов означает одно и то же
- Пусть все соответствующие токены найдут одно и то же
Подводя итог, они действительно должны быть одинаковыми во всех возможных отношениях.
Во всех ваших сценариях foo
нарушает ODR, имея различную последовательность токенов.
Лучшим исправлением без изменения библиотек являются встроенные пространства имен
#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; };
}