不同的别名模板可以解决整个库中潜在的ODR违规问题吗?

时间:2019-02-13 08:37:13

标签: c++ type-alias one-definition-rule

我在大型代码库中有潜在的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; };
  1. 我猜foo<a>foo<b>没有违反ODR,对吗?
  2. 但是foo<c>a_helper带来的b_helper的不同定义简直令人难以置信,对吗?

要注意的是,我在一个大型项目中拥有此功能。另外,可能(但不确定)我只有不重叠的ab,而没有问题的a_helperb_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
  1. 现在,我们有了foo_impl和foo_double_impl的定义,而不是foo的两个不同定义。这样可以解决ODR违规问题吗?还是因为存在foo的两个不同别名模板而导致ODR违例持续存在?

1 个答案:

答案 0 :(得分:2)

ODR的指定时间相当长,in the standard可以归结为必须输入

  • 具有非内联函数或变量的确切定义
  • 至少对所有其他使用的东西都有一个定义。众多定义必须完全相同,包括
    • 具有相同的令牌序列
    • 令牌序列具有相同的含义
    • 让所有对应令牌的查找都找到相同的东西

总而言之,实际上它们确实在所有可能的方式上都是相同的。

在所有情况下,foo都有不同的令牌顺序,从而违反了ODR。


不更改库的最佳解决方法是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; };
}