在函数模板中将一个类型名称映射到另一个类型名称
Map one typename to another in a function template
我正在编写函数模板以使用 float
、double
、std::complex<float>
和 std::complex<double>
类型。
我经常需要声明一个对应于"same precision but purely real"的类型。所以 float
和 std::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); }
我正在编写函数模板以使用 float
、double
、std::complex<float>
和 std::complex<double>
类型。
我经常需要声明一个对应于"same precision but purely real"的类型。所以 float
和 std::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); }