【问题标题】:How does one increase precision in C++ templates in a template typename-dependent manner?如何以依赖于模板类型名的方式提高 C++ 模板的精度?
【发布时间】:2012-08-08 21:48:06
【问题描述】:

我有一个模板化的数学函数,它接受两个值,对它们进行一些数学运算,然后返回一个相同类型的值。

template <typename T>
T math_function(T a, T b) {
  LongT x = MATH_OP1(a,b);
  return MATH_OP2(x,a);
}

我想将中间值(在 x 中)存储在一个基本上是 T 的长版本(上面称为 LongT)的类型中。所以,如果 T 是浮点数,我希望 x 是双精度数;如果 T 是一个 int,我希望 x 是一个 long int。

有没有办法做到这一点?我试过enable_if,但似乎我真的需要enable_if_else

我宁愿让编译器自己弄清楚 LongT 使用什么。我宁愿在调用函数时不必指定它。

【问题讨论】:

    标签: c++ templates stl


    【解决方案1】:

    您可以定义将产生所需类型的类型映射:

    template <typename T> struct long_type;
    template <> struct long_type<int> {
       typedef long type;
    };
    template <> struct long_type<float> {
       typedef double type;
    };
    

    然后使用那个元函数:

    template <typename T>
    T math_function(T a, T b) {
      typename long_type<T>::type x = MATH_OP1(a,b);
      return static_cast<T>(MATH_OP2(x,a));
    }
    

    使用此特定实现,您的模板将无法编译为您提供long_type 特征的类型以外的任何类型。您可能希望提供一个仅映射到自身的通用版本,以便如果输入是 long long int,则使用该版本(假设您的架构中没有更大的类型)。

    【讨论】:

    • 出于好奇,默认会是什么样子?
    • @mohawkjohn:基本模板将被定义(在答案中仅声明)为template &lt;typename T&gt; struct long_type { typedef T type; };,也就是说,对于我们所针对的任何类型不知道更大的类型,在内部使用该类型
    【解决方案2】:

    假设您不需要处理 T=long 例如,只需为 intfloat 创建特征:

    template <typename T>
    struct LongT;
    
    template <>
    struct LongT<int>
    {
        typedef long value_type;
    };
    
    template <>
    struct LongT<float>
    {
        typedef double value_type;
    };
    
    template <typename T>
    T math_function(T a, T b) {
      typename LongT<T>::value_type x = MATH_OP1(a,b);
      return MATH_OP2(x,a);
    }
    

    【讨论】:

      【解决方案3】:

      在 C++11 中,您可以使用 auto 关键字来检索 MATH_OP 的类型。它是安全的,由编译器处理。

      auto x = MATH_OP1(a,b);
      

      【讨论】:

      • 我不认为auto 是解决方案。我的理解是他想将类型提升为更大的类型,在那里执行操作(避免溢出),然后将解决方案推回原始类型。例如:average( MAX_INT, MAX_INT) 可以实现为int average( int a, int b ) { long long _a = a, _b = b; return static_cast&lt;int&gt;( (_a+_b)/2 ); }。在这种情况下,auto 不会解析为 long long,而是解析为 int,中间值可能会溢出。
      【解决方案4】:
      template<typename T> struct LongT  {typedef T type;}
      
      template<> struct LongT<int8_t>    {typedef int16_t type;}
      template<> struct LongT<int16_t>   {typedef int32_t type;}
      template<> struct LongT<int32_t>   {typedef int64_t type;}
      template<> struct LongT<int64_t>   {typedef intmax_t type;}
      // same for unsigned ...
      
      template<> struct LongT<float>     {typedef double type;}
      // template<> struct LongT<double> {typedef long double type;}
      

      这样使用:

      typename LongT<T>::type  x;
      

      【讨论】:

      • 非常感谢。实际上,我在 NMatrix(Ruby 矩阵库)中几乎逐字逐句地使用您的代码,但我必须给最先回答的人打勾。
      【解决方案5】:

      您可以编写自己的结构的专业化,或使用类似的东西

      #include <type_traits>
      
      template<typename T>
      void func(const T& f, const T& s)
      {
         typename std::conditional
         <
            std::is_same<T, float>::value,
            double,
            typename std::conditional
            <
              std::is_same<T, int>::value,
              long,
              void
            >::type
         >::type X(f + s);
         (void)X;
      }
      
      int main()
      {
         func(1, 1);
         func(1.0f, 1.0f);
         func(1.0, 1.0);
      }
      

      http://liveworkspace.org/code/8f75236b880a3fe210a8751e485a47ed

      但是按照大卫或马克的建议写你自己的专业。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-31
        • 2013-03-26
        • 1970-01-01
        • 1970-01-01
        • 2017-09-08
        • 2013-03-03
        相关资源
        最近更新 更多