1

これらのシグネチャを持つ dotProduct メソッドがあります。

template<typename It, typename It2>
typename DetermineResultType< typename std::iterator_traits<It>::value_type, typename std::iterator_traits<It2>::value_type>::Result dotProduct(It source, It2 source, const size_t size);

template<typename R, typename It, typename It2>
R dotProduct(It source, It2 source, const size_t size);

私が試すまで、すべてがうまくいきます:

char * s, * s2;
int result = dotProduct<int>(s, s2, 3);

std::iterator_traits<int>::value_typeこれにより、定義されていないエラーが発生します。

最初の宣言の結果の型を自動的に決定できるようにするには、どうすればこれを解決できますか? (メソッドの名前は同じでなければなりません)。結果の型を決定するためにいくつかの規則を採用していますが、これは重要ではありません。

基本的に、問題std::iterator_traits<It>::value_typeは定義されているかどうかに要約されます-特殊化されていない std::iterator_traits が使用されている場合。どうにかしてこれを検出できますか?そうでない場合、他にどのようなオプションがありますか?

わかりました、下の例が機能するようになりましたが、同じトリックを行うにはどうすればよいですか?

    //! Template IF predicate implementation
  template <bool B, typename TrueResult, typename FalseResult> 
 class TemplateIf {
 public:
   //! The result of template IF predicate
   typedef TrueResult Result;
 };

 //! Template IF predicate implementation - specialization for false condition
 template <typename TrueResult, typename FalseResult>
 class TemplateIf<false, TrueResult, FalseResult> {
 public:
   //! The result of template IF predicate
   typedef FalseResult Result;
 };



  template <typename T1, typename T2>
  class DetermineComputationType {
  public:
    //! The determined result type
    // If (isSpecialized(T1) && isSpecialized(T2)) {
    typedef typename TemplateIf< std::numeric_limits<T1>::is_specialized && std::numeric_limits<T2>::is_specialized,
      // If (! isInteger(T1) && isInteger(T2) )
      //   return T1;
      typename TemplateIf< ! std::numeric_limits<T1>::is_integer && std::numeric_limits<T2>::is_integer, T1,
      // Else if (! isInteger(T2) && isInteger(T1) )
      //   return T2;
      typename TemplateIf< ! std::numeric_limits<T2>::is_integer && std::numeric_limits<T1>::is_integer, T2,
      // Else if ( sizeof(T1) > sizeof(T2) )
      //   return T1;
      typename TemplateIf< (sizeof(T1) > sizeof(T2)), T1,
      // Else if ( sizeof(T2) > sizeof(T1) )
      //   return T2;
      typename TemplateIf< (sizeof(T2) > sizeof(T1)), T2,
      // Else if ( isSigned(T2) )
      //   return T1;
      // Else
      //   return T2; 
      // }
      typename TemplateIf< std::numeric_limits<T2>::is_signed, T1, T2>::Result >::Result >::Result >::Result >::Result,
      // Else if ( sizeof(T2> > sizeof(T1) )
      //   return T2;
      // Else
      //   return T1;
      typename TemplateIf< (sizeof(T2) > sizeof(T1)), T2, T1 >::Result >::Result Result;
  };


   /*!
\brief Helper class for computation type determination - works for 3 types 

\tparam T1 The first type for computation type determination
\tparam T2 The second type for computation type determination 
\tparam T3 The third type for computation type determination

The result is computed in order: (T1, (T2, T3))
*/
template <typename T1, typename T2, typename T3>
class DetermineComputationType2 {
public:
//! The computation type result
typedef typename DetermineComputationType<T1, typename DetermineComputationType<T2, T3>::Result >::Result Result;
 };

template <typename T1, typename T2>
class DetermineReturnComputationType {
public:    
typedef typename std::iterator_traits<T1>::value_type T1Type;
typedef typename std::iterator_traits<T2>::value_type T2Type;    
typedef typename DetermineComputationType<T1Type, T2Type>::Result Result;
};

//! For description see cpputil::dotProduct()
 template <typename R, typename Ct, typename It, typename It2>
 inline R dotProductRCtItIt2(It source, It2 source2, const size_t size) {
   Ct result = Ct();
   for (size_t i = 0; i < size; ++i)
     result += static_cast<Ct>(source[i]) * static_cast<Ct>(source2[i]);

   return static_cast<R>(result);
  }


/*!
\brief Returns the dot product of vectors

\param[in] source The iterator to the start of source vector
\param[in] source2 The iterator to the start of second source vector    
\param[in] size The size of vector(s)
*/
template <typename R, typename Ct, typename It, typename It2>
inline R dotProduct(It source, It2 source2, const size_t size) {
  return arithmeticsInternal::dotProductRCtItIt2<R, Ct, It, It2>(source, source2, size);  
}

//! Convenience method - see above for description
template <typename R, typename It, typename It2>
inline R dotProduct(It source, It2 source2, const size_t size) {
  typedef typename std::iterator_traits<It>::value_type ItType;
  typedef typename std::iterator_traits<It2>::value_type It2Type;
  typedef typename arithmeticsInternal::DetermineComputationType2<R, ItType, It2Type>::Result Ct;

 return arithmeticsInternal::dotProductRCtItIt2<R, Ct, It, It2>(source, source2, size);
}

//! Convenience method - see above for description
template <typename It, typename It2>
inline typename arithmeticsInternal::DetermineReturnComputationType<It, It2>::Result dotProduct(It source, It2 source2, const size_t size) {
 //typedef typename std::iterator_traits<It>::value_type ItType;
 //typedef typename std::iterator_traits<It2>::value_type It2Type;
 typedef typename arithmeticsInternal::DetermineReturnComputationType<It, It2>::Result R;

 return arithmeticsInternal::dotProductRCtItIt2<R, R, It, It2>(source, source2, size);  
 }   
4

1 に答える 1

1

戻り値の型を推測するか、明示的に指定できるようにする dotProduct テンプレート関数を取得する方法の例を次に示します。

#include <stdlib.h>
#include <iterator>
#include <iostream>

using std::cerr;

template<typename It, typename It2> struct DetermineResultType;

template<>
struct DetermineResultType<char,char> {
  typedef int Result;
};

template <typename It1,typename It2>
struct DotProduct {
  typedef typename std::iterator_traits<It1>::value_type VT1;
  typedef typename std::iterator_traits<It2>::value_type VT2;
  typedef typename DetermineResultType<VT1,VT2>::Result Result;
};

template<typename Result,typename It, typename It2>
Result dotProduct(It source1, It2 source2, const size_t size)
{
  Result sum = 0;
  for (size_t i=0; i!=size; ++i) {
    sum += *source1 * *source2;
  }
  return sum;
}

template<typename It1, typename It2>
typename DotProduct<It1,It2>::Result
  dotProduct(It1 source1, It2 source2, const size_t size)
{
  typedef typename DotProduct<It1,It2>::Result Result;
  return dotProduct<Result>(source1,source2,size);
}


int main(int argc,char **argv)
{
  const char *s1 = "abc";
  const char *s2 = "def";
  cerr << dotProduct<int>(s1,s2,3) << "\n";
  cerr << dotProduct(s1,s2,3) << "\n";
  return EXIT_SUCCESS;
}

最初のパラメーターがイテレーターでない場合、コンパイラーは VT1 のタイプを判別できないため、DotProduct<> のインスタンス化に失敗します。SFINAE はその過負荷を解消します。

于 2012-08-02T14:48:32.890 に答える