c++ - 如何解决自动返回类型 - C++(模板)

标签 c++ templates sfinae

我有一个带有这些签名的 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 时。我能以某种方式检测到这个吗? 如果不是,我还有什么其他选择?

好的,现在这个例子可以工作了,但是我如何做同样的事情我的 DetermineComputationType aka DetermineResultType 是这样定义的:???

    //! 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);  
 }   

最佳答案

下面是一个如何获取 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;
}

如果第一个参数不是迭代器,那么编译器将无法实例化 DotProduct<>,因为它无法确定 VT1 的类型。然后 SFINAE 将消除该过载。

关于c++ - 如何解决自动返回类型 - C++(模板),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11779049/

相关文章:

C++ 相互模板依赖?

c++ - TS Concepts 类型名约束

c++ - 如何检查 operator== 是否存在?

c++ - 如何将不可复制类型的引用传递给 SFINAE "catch-all"重载函数?

c++ - 放置复杂物体

c++ - 带有部分符号的遗留 proc C/C++ 代码(§)

c++ - 如何为 YAML::Emitter 重载 << 运算符以序列化包含另一个自定义类的 vector 的自定义类

c++ - 重载模板类

c++ - SFINAE 有选择地纳入成员(member)

c++ - 与 vector 关联的 NULL 指针