【问题标题】:ODR violation with template specializations模板专业化的 ODR 违规
【发布时间】:2017-07-20 09:24:27
【问题描述】:

我们有一个头文件,其中包含各种浮点精度的一些残差:

template <typename T>
struct rsdTarget {
  static const double value;
};

template <>
const double rsdTarget<half>::value = (double)(1.0e-3);

template <>
const double rsdTarget<float>::value = (double)(1.0e-7);

template <>
const double rsdTarget<double>::value = (double)(1.0e-12);

这很有效,因为这个头文件只包含在一个编译单元中。现在我尝试在多个编译单元中使用这个头文件,我得到了源于 ODR 的链接器错误:

CMakeFiles/tests_g.dir/random_gauge.cc.o:(.rodata+0x108): multiple definition of `rsdTarget<double>::value'
CMakeFiles/tests_g.dir/clover_product.cc.o:(.rodata+0x548): first defined here

初始化可能需要进入源文件并从头文件中取出。但是,似乎禁止在const double 前面加上extern

我必须怎么做才能使其适用于多个编译单元?

更新

我认为为double 解决这个问题会完全解决它。但是,我还必须执行第二种非文字类型:

template <typename T>
struct tolerance {
  static const QDP::Double small; // Always fail
};

template <>
const QDP::Double tolerance<half>::small = QDP::Double(5.0e-3);

template <>
const QDP::Double tolerance<float>::small = QDP::Double(1.0e-6);

template <>
const QDP::Double tolerance<double>::small = QDP::Double(1.0e-7);

我似乎无法将它与constexpr 一起使用,因为该类型不支持它(需要constexpr ctor,对吗?)。哪些解决方案也适用于此?

【问题讨论】:

  • 在专业化上使用inline。 (如果您使用的是最新的编译器,请考虑将其替换为内联变量)
  • 您也可以在 Microsoft 编译器的模板专业化之前使用__declspec(selectany)
  • 内联变量似乎需要C++17,我们现在只到C++11。它是一种高性能代码,需要在编译器版本不可预测的各种 HPC 系统上运行。我会试着摆弄内联。
  • @ikleschenkov:我没有看到我们使用过微软编译器。我们使用 GCC、Clang、IBM XLC(虽然不适用于此代码)、英特尔 C++ 和 Cray 编译器。我们的目标系统在 Linux 上运行 :-)。
  • 我已经更新了问题,因为问题比我想象的要严重。很抱歉!

标签: c++ c++11 one-definition-rule


【解决方案1】:

当在多个翻译单元中使用时,您可以允许所有这些定义驻留在头文件中而不会导致链接器错误,您只需将它们也转换为模板:

template<typename T, typename TDummy = void>
struct rsdTarget;

template<typename TDummy>
struct rsdTarget<half, TDummy>
{
    static const double value;
};

template<typename TDummy>
const double rsdTarget<half, TDummy>::value = (double)(1.0e-3);

template<typename TDummy>
struct rsdTarget<float, TDummy>
{
    static const double value;
};

template<typename TDummy>
const double rsdTarget<float, TDummy>::value = (double)(1.0e-7);

template<typename TDummy>
struct rsdTarget<double, TDummy>
{
    static const double value;
};

template<typename TDummy>
const double rsdTarget<double, TDummy>::value = (double)(1.0e-12);

【讨论】:

    【解决方案2】:

    以前的 C++1z

    template<typename>
    struct rsdTarget;
    
    template<>
    struct rsdTarget<half>
    {
        static constexpr double value = 1e-3;
    };
    
    // and so on...
    

    这有一个限制,value 不能被 odr 使用,但在大多数情况下,这对于常量来说不是问题。

    发布 C++1z,您可以只使用 inline 变量并避免整个 odr 惨败。

    【讨论】:

    • 你可以通过定义避免odr-use问题
    • @M.M 但是我们又回到了同样的问题,只有const,在这种特殊情况下,这违背了constexpr 的目的。
    猜你喜欢
    • 2011-09-23
    • 1970-01-01
    • 1970-01-01
    • 2020-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-28
    • 2015-08-01
    相关资源
    最近更新 更多