2016-06-27 3 views
6

から*明確な戻り値の型*を持つテンプレートクラスの特殊化、テンプレート機能をコンパイルに失敗しますが、打ち鳴らす3.8に失敗します。クランは機能<code>derefItemX()</code>次GCC 4.8から5.3に罰金コンパイルされたテンプレート宣言

//! 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()は、値または元の値の値へのポインタのいずれかの反復子を参照します。 あまり言う:クランは、次のエラーメッセージが表示さ

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) 
            ^~~~~~~~~~ 

を誰も説明していただけます。

  1. なぜ打ち鳴らすにはderefItemX()のコンパイルに失敗するのか?
  2. 異なるコンパイラで動作する別のアプローチを使用して、* xまたは** xに参照解除されるイテレータをパラメータ化する方法はありますか?

ありがとうございます!

注:戻り型が指定されている場合
同じ問題は、C++ 11のために存在するが、テンプレート宣言と専門で異なります。
CLangは、標準に従って関数シグニチャの一部ではない戻り値の型(テンプレートクラス宣言と特殊化のテンプレート関数)と一致する必要があります。 @ max66で指定されている "クロスコンパイラ"ソリューションは、テンプレートクラスと必要な特殊化の宣言を空にすることです。

+1

プロペでr [mcve]、あなたはより多くの助けを得るかもしれません。 – AndyG

+1

特殊機能は恐ろしい考えです。 *常に*クラスを特化するか、名前空間のスコープで関数をオーバーロードする。 – o11c

+0

@ o11cあなたが見ることができるように、関数の部分的な特殊化は標準によって許可されていないので、クラスは特殊化された関数ではありません。 オーバーロードは場合によってはオプションですが、バーチャルテーブルの使用が全体の実行速度に影響する高性能コードでは使用できません。 – luart

答えて

4

一般的な方法で問題を解決する方法はありません。この問題(私が間違っていない場合)は、クラス全体を専門にすることができます。 「打ち鳴らすは、コンパイルに失敗する理由」問題に関しては

#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 
     } 
}; 

ような何か...私は混乱していると私はgの玉葉権利を知らない++と打ち鳴らす++

PS:私の悪い英語のため申し訳ありません

+0

ありがとうございました!あなたは正しいです、完全な専門はすべてのコンパイラで動作します! – luart

+0

@luart - あなたのおかげで:あなたの問題を理解しようとしています。なぜg ++があなたのサンプルをコンパイルするのか理解しているanc clang ++;私はアイデアがあったが間違っていた – max66

0

私は最近、すべてのコンパイラで正常に動作し、(明示的なパラメータなし)ずっと優雅問題を解決std::enable_if<>を使用して、そのテンプレートを、書き直し:

//! \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; 
} 
関連する問題