代码之家  ›  专栏  ›  技术社区  ›  KQS

将函数模板中的一个类型名映射到另一个类型名

  •  2
  • KQS  · 技术社区  · 7 年前

    我正在编写函数模板 float , double , std::complex<float> std::complex<double> 类型。

    我经常需要声明一个对应于“相同精度但纯实数”的类型。所以两者都是 标准::复杂<浮动(>); 将映射到

    我一直在用超负荷来做这件事,比如:

    template <typename numeric_t, typename real_t>
    numeric_t foo(numeric_t x) {
        real_t y = abs(x);
        return x/y;
    }
    
    template <typename T> // Used when x is real
    T bar(T x) { return foo<T,T>(x); }
    
    template <typename T> // Overload takes precedence when x is complex
    complex<T> bar(complex<T> x) { return foo<complex<T>,T>(x); }
    

    但这似乎相当麻烦,尤其是因为我需要为我编写的每个这样的函数定义它们。有更好的方法吗?


    在这个例子中,我可以做到:

    template <typename numeric_t>
    numeric_t bar(numeric_t x) {
        auto y = abs(x);
        return x/y;
    }
    

    因为 abs() 已适当超载。这太棒了!这正是我想要的。但如果我不打电话呢 abs ? 或者如果 real_t 是返回类型吗?

    1 回复  |  直到 7 年前
        1
  •  2
  •   max66    7 年前

    如果定义一个简单的类型traits来检测正确的返回类型,如下所示 realType

    template <typename T>
    struct realType
     { using type = T; };
    
    template <typename T>
    struct realType<std::complex<T>>
     { using type = T; };
    

    这个 bar() 函数可以写成

    template <typename T>
    T bar (T const & x)
     { return foo<T, typename realType<T>::type>(x); }
    

    #include <complex>
    
    template <typename T>
    struct realType
     { using type = T; };
    
    template <typename T>
    struct realType<std::complex<T>>
     { using type = T; };
    
    template <typename numeric_t, typename real_t>
    numeric_t foo(numeric_t x)
     {
       real_t y = abs(x);
       return x/y;
     }
    
    template <typename T>
    T bar (T const & x)
     { return foo<T, typename realType<T>::type>(x); }
    
    int main ()
     {
       using type1 = decltype(bar<float>(1.0f));
       using type2 = decltype(bar<std::complex<double>>(1.0));
    
       static_assert(std::is_same<type1, float>{}, "!");
       static_assert(std::is_same<type2, std::complex<double>>{}, "!");
     }
    

    离题建议。

    foo() 函数有两种模板类型,但只有第一种( numeric_t )可以从输入参数推断( x ). 因此,你必须明确这两个方面。

    如果反转模板类型的顺序

    template <typename real_t, typename numeric_t>
    numeric_t foo(numeric_t x)
     {
       real_t y = abs(x);
       return x/y;
     }
    

    你可以打电话 foo() 只解释第一个,让编译器推导第二个;所以 条形图()

    template <typename T>
    T bar (T const & x)
     { return foo<typename realType<T>::type>(x); }
    

    --编辑--

    根据aschepler的建议(谢谢!)你可以推导出 real_t 输入 foo() 从…起 数字\u t ; 因此,无需切换这两种模板类型,您就可以编写 foo() 如下所示

    template <typename numeric_t,
              typename real_t = typename realType<numeric_t>::type>
    numeric_t foo(numeric_t x)
     {
       real_t y = abs(x);
       return x/y;
     }
    

    条形图() 简单地成为

    template <typename T>
    T bar (T const & x)
     { return foo(x); }