2016-07-29 6 views
0

Может кто-нибудь, пожалуйста, объяснить: 1) почему приведенный ниже код не работает на лязг и 2), как это должно быть переписан, чтобы быть совместимым с лязгом ?Динамическое связывание терпит неудачу на Clang для constexpr статического члена полностью специализированного шаблона

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, но имеет ошибку на связующую лязгом 3.8.1 на Linux Ubuntu x64:

неопределенная ссылка на `InpLink :: вес»

После определения:

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 параметра в шаблоне, выполните частичную специализацию и определите статический вес 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 или с моей полной специализацией по шаблону?

ответ

0

Итак, кажется, что это ошибка в CLang < = 3.8.1, которая ограничивает использование constexpr для статических членов в динамических библиотеках и предотвращает отдельное определение статических членов полностью специализированных шаблонов.
И способ преодолеть это:
1. Используйте static const вместо constexpr для CLang.
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 по-прежнему имеет некоторые уникальные преимущества для отладки).