【问题标题】:Can differing alias templates resolve potential ODR violations across libraries?不同的别名模板能否解决跨库的潜在 ODR 违规?
【发布时间】:2019-02-13 08:37:13
【问题描述】:

我在大型代码库中发生了潜在的 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&lt;a&gt;foo&lt;b&gt; 没有违反 ODR,对吗?
  2. 但是 foo&lt;c&gt;a_helperb_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 违规仍然存在?

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-29
      • 2020-04-03
      • 1970-01-01
      相关资源
      最近更新 更多