对于完全专用模板的constexpr静态成员,CLang上的动态链接失败

时间:2016-07-29 17:59:35

标签: c++ templates clang dynamic-linking constexpr

任何人,请解释1)为什么下面的代码不适用于CLang 2)如何将其重写为与CLang兼容

using LinkWeight = float;

template <bool WEIGHTED=true>
struct InpLink {
    using Weight = LinkWeight;  //!< \copydoc LinkWeight
    Weight  weight;  //!< Link weight
    // ...
};

template <>
struct InpLink<false> {
    using Weight = LinkWeight;  //!< \copydoc LinkWeight
    constexpr static Weight  weight = 1;
};

此代码在GCC上运行正常,但在Linux Ubuntu x64上的CLang 3.8.1上存在链接错误:

  

对“InpLink :: weight”的未定义引用

定义后:

template <>
constexpr typename InpLink<false>::Weight  InpLink<false>::weight;

编译时错误是:extraneous 'template<>' in declaration of variable 'weight'

定义后:

template <bool WEIGHTED>
constexpr typename InpLink<false>::Weight  InpLink<false>::weight;

编译时错误是:

..cluster.hpp:31:60: error: redefinition of 'weight' as different kind of symbol
constexpr typename InpLink<false>::Weight  InpLink<false>::weight;
                                                           ^
..cluster.h:58:27: note: previous definition is here
        constexpr static Weight  weight = 1;

这看起来像一个CLang的bug ...

注意:如果我在模板中有2个参数,执行部分特化并将静态constexpr权重定义为:,则相同的示例在CLang上正常工作

template <bool TMP>
constexpr typename InpLink<false, TMP>::Weight  InpLink<false, UNSIGNED>::weight;

具有

template <bool WEIGHTED=true, bool TMP=true>
struct InpLink {
    using Weight = LinkWeight;  //!< \copydoc LinkWeight
    Weight  weight;  //!< Link weight
    // ...
};

template <bool TMP>
struct InpLink<false, TMP> {
    using Weight = LinkWeight;  //!< \copydoc LinkWeight
    constexpr static Weight  weight = 1;
};

显然我不想使用额外的模板参数来克服链接错误。还有其他方法可以解决这个问题吗? CLang 3.8.1或我的完整模板专业化有什么问题?

1 个答案:

答案 0 :(得分:0)

因此,似乎这是CLang&lt; = 3.8.1中的一个错误,它限制了动态库中静态成员对constexpr的使用,并阻止了对完全专用模板的静态成员的单独定义。
克服它的方法是:
1.对CLang使用static const而不是constexpr 2.定义仅与模板声明相对应的静态成员,而不是完整的专业化:

template <bool WEIGHTED=false>
struct InpLink {
    using Weight = LinkWeight;  //!< \copydoc LinkWeight

    //! Link is unweighted
    constexpr static bool  IS_WEIGHTED = false;
    //! \copydoc SimpleLink<Weight>::weight
    // ATTENTION: such complicated definition is required to overcome
    // the linking error on CLang
#ifdef __clang__
    const
#else
    constexpr
#endif // __clang__
    static Weight  weight
#ifndef __clang__
        = 1
#endif // !__clang__
    ;
    // ...
};

template <>
struct InpLink<true> {
    using Weight = LinkWeight;  //!< \copydoc LinkWeight
    Weight  weight;  //!< Link weight
    // ...
};

并将.cpp中的静态权重定义为:

#ifdef __clang__
// Note: Required by CLang for the linking
template <>
const InpLink<false>::Weight  InpLink<false>::weight = 1;
#endif  // __clang__
对于发布版本来说,PS GCC实际上是一个比CLang更好,更可靠的编译器(CLang仍然有一些独特的调试优势)。