2016-06-27 9 views
6

Poniższa funkcja derefItemX() jest kompilowany na GCC 4.8-5.3 porządku, ale nie na Clang 3.8:Clang nie skompilować funkcję szablonu w specjalizacji klasy szablon, który ma odrębny typ zwracany * * od deklaracji szablonu

//! Accessory Operations - template argument depended wrappers 
template<bool SIMPLE> // For Nodes/non-scoped storage 
struct Operations { 
    //! \brief Defererence wrapped or direct iterator 
    //! 
    //! \param iel IItemXT& - iterator to be dereferenced 
    //! \return ItemT& - resulting reference 
    template<typename IItemXT> 
    constexpr static auto& derefItemX(IItemXT& iel) 
    { 
     static_assert(is_base_of<std::forward_iterator_tag, typename IItemXT::iterator_category>::value 
      , "derefItemX(), IItemXT must be a forward iterator type"); 
     return **iel; // Dereference an iterator of pointer to the value 
    } 
}; 

//! Specialization for non-scoped storage (direct pointers) 
template<> 
template<typename IItemXT> 
constexpr auto& Operations<true>::derefItemX(IItemXT& iel) 
{ 
    static_assert(is_base_of<std::forward_iterator_tag, typename IItemXT::iterator_category>::value 
     , "derefItemX(), IItemXT must be a forward iterator type"); 
    return *iel; // Dereference an iterator of value to the value 
} 


... 
// Usage: 
auto& el = Operations<!is_pointer<typename IItemXT::value_type> 
      ::value>::derefItemX(ic); 

derefItemX() odejmuje iterator wartości lub wskaźnika do wartości początkowej. Dzyń pojawi się następujący komunikat o błędzie: który mówi niewiele:

include/hierarchy.hpp:168:35: error: out-of-line definition of 'derefItemX' does not match any declaration in 'XXX::Operations<true>' 
constexpr auto& Operations<true>::derefItemX(IItemXT& iel) 
            ^~~~~~~~~~ 

Czy ktoś proszę wyjaśnić:

  1. Dlaczego Clang nie skompilować derefItemX()?
  2. Jak sparametryzować dereferencję iteratora na * x lub ** x używając innej metody, która działałaby na różnych kompilatorach?

Wielkie dzięki!

Uwaga:
Ten sam problem istnieje dla C++ 11, gdy jest określony typ zwracany, ale różni w deklaracji szablonu i specjalizacji.
Wygląda na to, że CLang wymaga dopasowania typów zwracanych (funkcji szablonu w deklaracji i specjalizacji klasy szablonów), które nie są częścią podpisu funkcji zgodnie ze standardem. Rozwiązanie "cross-kompilator" określone przez @ max66 ma mieć pustą deklarację klasy szablonu i wymaganych specjalizacji.

+1

z salo r [mcve], możesz uzyskać więcej pomocy. – AndyG

+1

Funkcje specjalistyczne to straszny pomysł. * zawsze * specjalizuj klasy lub funkcje przeciążeniowe w obszarze przestrzeni nazw. – o11c

+0

@ o11c jak widać klasa jest wyspecjalizowana, a nie funkcja, ponieważ częściowa specjalizacja funkcji nie jest dozwolona przez standard. Przeciążenie jest opcją w niektórych przypadkach, ale nie dla kodu o wysokiej wydajności, w którym użycie wirtualnych tabel wpływa na całkowitą szybkość wykonania. – luart

Odpowiedz

4

Nie rozumiem, jak rozwiązać problem w sposób ogólny; ale ten problem (jeśli się nie mylę) można rozwiązać specjalizując całą klasę; coś

#include <iterator> 
#include <type_traits> 

using namespace std; 

template <bool> 
struct Operations; 

template<> 
struct Operations<false> { 
    template<typename IItemXT> 
     constexpr static auto& derefItemX(IItemXT& iel) 
     { 
     static_assert(is_base_of<std::forward_iterator_tag, typename IItemXT::iterator_category>::value 
         , "derefItemX(), IItemXT must be a forward iterator type"); 
     return **iel; // Dereference an iterator of pointer to the value 
     } 
}; 

template<> 
struct Operations<true> { 
    template<typename IItemXT> 
     constexpr auto& derefItemX(IItemXT& iel) 
     { 
     static_assert(is_base_of<std::forward_iterator_tag, typename IItemXT::iterator_category>::value 
         , "derefItemX(), IItemXT must be a forward iterator type"); 
     return *iel; // Dereference an iterator of value to the value 
     } 
}; 

Odnośnie problemu „dlaczego dzyń nie kompilacji” ... Jestem zdezorientowany i nie wiem kogo dokładnie między g ++ i brzękiem ++

PS: Przepraszam za mój zły język angielski

+0

Dziękuję Max! Masz rację, pełna specjalizacja działa na wszystkich kompilatorach! – luart

+0

@luart - Dzięki tobie: próbując zrozumieć twój problem, odkryłem rzeczy o C++ 14, których nigdy nie podejrzewałem; pozostać, aby zrozumieć, dlaczego g ++ skompilować twój przykład anc clang ++ not; Miałem pomysł, ale myliłem się – max66

0

niedawno przepisał tego szablonu przy użyciu std::enable_if<>, który działa poprawnie na wszystkich kompilatorów i rozwiązuje problem znacznie wdzięcznie (bez wyraźnej parametru):

//! \brief Defererence wrapped or direct iterator 
//! 
//! \param iel IItemXT - iterator to be dereferenced 
//! \return ItemT& - resulting reference 
template <typename IItemXT, enable_if_t<is_pointer<typename iterator_traits<IItemXT>::value_type>::value>* = nullptr> 
constexpr auto derefIterX(IItemXT iel) -> remove_pointer_t<typename iterator_traits<IItemXT>::value_type>& 
{ 
    static_assert(is_iterator<IItemXT>(), "derefIterX(), IItemXT must be a forward iterator type"); 
    return **iel; 
} 

template <typename IItemXT, enable_if_t<!is_pointer<typename iterator_traits<IItemXT>::value_type>::value, bool>* = nullptr> 
constexpr auto derefIterX(IItemXT iel) -> typename iterator_traits<IItemXT>::reference 
{ 
    static_assert(is_iterator<IItemXT>(), "derefIterX(), IItemXT must be a forward iterator type"); 
    return *iel; 
} 
Powiązane problemy