c++ - 不同的别名模板能否解决跨库的潜在 ODR 违规问题?

标签 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 违规问题?还是 ODR 违规持续存在是因为 foo 有两个不同的别名模板?

最佳答案

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; };
}

关于c++ - 不同的别名模板能否解决跨库的潜在 ODR 违规问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54665728/

相关文章:

c++ - 在我自己的命名空间中定义 size_t 会产生歧义或其他错误吗?

c++ - 我能保证不会被这种 ODR 违规行为所困扰吗?

c++ - 在多个类中实现堆栈时的单一定义规则 (ODR)

c++ - CGAL::Surface_mesh_parameterization: 把顶点写到off按原来的顺序

c++ - Minecraft 类碰撞

ios - 带有协议(protocol)问题的快速类型别名

scala - 在 scala 中,如何使类型类适用于 Aux 模式? - 第2部分

c++ - 为什么将 set::iterator 而不是 const_iterator 传递给函数会违反单一定义规则?

c++ - 值参数的 const 正确性

c++ - 如何确定进程设置为 REAL_TIME 优先级