简体   繁体   English

模板专业化违反ODR

[英]ODR violation with template specializations

We have a header file which contains some residuals for various floating point precisions: 我们有一个头文件,其中包含一些用于各种浮点精度的残差:

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

This has worked because this header had only been included in a single compilation unit. 之所以可行,是因为该标头仅包含在一个编译单元中。 Now I try to use this header in multiple compilation units and I get linker errors stemming from the ODR: 现在,我尝试在多个编译单元中使用此标头,并且由于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

The initialization probably needs to go into a source file and be taken out of the header file. 初始化可能需要进入源文件并从头文件中取出。 However it seems to be prohibited to but an extern in front of the const double . 但是,似乎只能在const double前面加一个extern

What would I have to do such that this works with multiple compilation units? 我该怎么做才能与多个编译单元一起使用?

Update 更新

I thought that solving this for double would fix it fully. 我认为,解决这一对double会完全修复它。 However, there is a second non-literal type which I also have to carry through: 但是,还有第二种非文字类型,我也必须经历:

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

I cannot seem to use that with constexpr because that type does not support it ( constexpr ctor needed, right?). 我似乎无法在constexpr使用它,因为该类型不支持它(需要constexpr ctor,对吗?)。 Which of the solutions works with this as well? 哪种解决方案也适用?

You can allow all these definitions reside in the header file without causing linker errors when it is used in multiple translation units, you just need to turn them into templates as well: 您可以允许所有这些定义驻留在头文件中,而在多个翻译单元中使用时,也不会引起链接器错误,只需将它们也转换为模板即可:

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

Prior C++1z 先前的C ++ 1z

template<typename>
struct rsdTarget;

template<>
struct rsdTarget<half>
{
    static constexpr double value = 1e-3;
};

// and so on...

This has a restriction that value cannot be odr-used, but in most cases, this is not a problem for constants. 这具有限制value不能ODR使用的,但在大多数情况下,这是不是常数的一个问题。

Post C++1z, you could just use inline variables and avoid the whole odr fiasco. 在C ++ 1z之后,您可以只使用inline变量,而避免整个odr惨败。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM