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

Map one typename to another in a function template

我正在编写函数模板以使用 floatdoublestd::complex<float>std::complex<double> 类型。

我经常需要声明一个对应于"same precision but purely real"的类型。所以 floatstd::complex<float> 都会映射到 float,等等

我一直在用这样的重载来做这件事:

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 是 return 类型?

如果你定义一个检测正确return类型的简单类型特征,像下面这样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() 函数有两种模板类型,但只能从输入参数 (x) 中推导出第一种 (numeric_t)。所以你不得不明确他们两个。

如果颠倒模板类型的顺序

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

你可以调用foo()只解释第一个,让编译器推导出第二个;所以 bar() 可以写成

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

-- 编辑--

按照 aschepler 的建议(谢谢!),您可以从 numeric_t 中推断出 foo() 中的 real_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;
 }

bar()就变成了

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