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

Dynamic linking fails on CLang for constexpr static member of fully specialized template

谁能解释一下 1) 为什么下面的代码不能在 CLang2 上工作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 上存在链接错误

undefined reference to `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 错误...

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

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 或我的完整模板专业化有什么问题?

所以,这似乎是 CLang <= 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 中定义静态权重而不是 header 为:

#ifdef __clang__
// Note: Required by CLang for the linking
template <>
const InpLink<false>::Weight  InpLink<false>::weight = 1;
#endif  // __clang__

PS 对于发布版本,GCC 确实比 CLang 好得多、可靠得多(CLang 仍然有一些独特的调试优势)。