std::complex 的模板函数重载
Template function overload for std::complex
我有一个函数可以为我的数组生成随机数。我为浮点数和整数创建了两个重载,如下所示:
template <typename T, int M = 0>
typename std::enable_if<std::is_floating_point<T>::value && std::is_scalar<T>::value,MyArray<T,M> >::type
Random()
{
//...
}
template <typename T, int M = 0>
typename std::enable_if<std::is_integral<T>::value && std::is_scalar<T>::value, MyArray<T,M> >::type
Random()
{
//...
}
可以通过以下方式调用这些函数:
MyArray<int> i = Random<int>();
MyArray<double> d = Random<double>();
我想实现相同但使用 std::complex<T>
,其中 T
可以是任何浮点类型(最初 double 和 float 就足够了)。我希望能够做到这一点:
//This is what I'm trying to achieve
MyArray<std::complex<double> > = Random<std::complex<double>>();
MyArray<std::complex<float > > = Random<std::complex<float >>();
我无法完全做到这一点,但能够做到:
Random<std::complex,double>()
使用模板模板参数,这不是我要找的。
如何让 <std::complex<double>>
(或浮动)的重载工作?
使用标签分派 select 您想要的重载。此代码需要 C++14,但可以很容易地使其与 C++11 一起使用。但是你会失去可读性(重复的函数体,没有enable_if_t
)
首先,定义标签:
struct integral_tag{};
struct floating_point_tag{};
struct complex_tag{};
struct error_tag{};
一些辅助模板(标签select离子,complex
检测):
namespace detail
{
template<typename T> struct is_complex : false_type {};
template<typename T> struct is_complex<complex<T>> : true_type {};
template<typename T, typename = void>
struct select { using type = error_tag; };
template<typename T>
struct select<T, enable_if_t<is_integral<T>::value>>{
using type = integral_tag;
};
template<typename T>
struct select<T, enable_if_t<is_floating_point<T>::value>>{
using type = floating_point_tag;
};
template<typename T>
struct select<T, enable_if_t<is_complex<T>::value>>{
using type = complex_tag;
};
}
并且每个重载+默认一个到select他们:
template<typename T>
using random_tag = typename detail::select<T>::type;
template<typename T>
auto Random(floating_point_tag){
return T{};
}
template<typename T>
auto Random(integral_tag){
return T{};
}
template<typename T>
auto Random(complex_tag){
return T{typename T::value_type{}, typename T::value_type{}+1};
}
template<typename T>
auto Random()
{
return Random<T>(random_tag<T>{});
}
然后你就可以使用它们了:
int main()
{
cout << Random<int>() << endl;
cout << Random<float>() << endl;
cout << Random<complex<double>>() << endl;
}
我想创建一个提取器助手(例如,从 std::complex<float>
中提取 float
)作为
template <typename T>
struct extractType;
template <template <typename ...> class C, typename D>
struct extractType<C<D>>
{ using subType = D; };
你可以用它写
template <typename T, int M = 0>
typename std::enable_if<std::is_same<T, std::complex<
typename extractType<T>::subType>>::value
&& std::is_floating_point<typename extractType<T>::subType>::value
&& std::is_scalar<typename extractType<T>::subType>::value,
MyArray<T,M> >::type
Random ()
{ return MyArray<T,M>{}; }
或者干脆
template <typename T, int M = 0>
typename std::enable_if<std::is_same<T,
std::complex<typename extractType<T>::subType>>::value,
MyArray<T,M> >::type
Random ()
{ return MyArray<T,M>{}; }
如果你能明显地认为 std::complex
的模板参数是浮动的和标量的。
--- 编辑 ---
添加了一个完整的示例(好吧...带有错误 MyArray
)
#include <array>
#include <complex>
#include <type_traits>
template <typename T, int M = 0>
using MyArray = std::array<T, 10U>;
template <typename T>
struct extractType;
template <template <typename ...> class C, typename D>
struct extractType<C<D>>
{ using subType = D; };
template <typename T, int M = 0>
typename std::enable_if<std::is_floating_point<T>::value && std::is_scalar<T>::value,MyArray<T,M> >::type
Random ()
{ return MyArray<T,M>{}; }
template <typename T, int M = 0>
typename std::enable_if<std::is_integral<T>::value && std::is_scalar<T>::value, MyArray<T,M> >::type
Random ()
{ return MyArray<T,M>{}; }
template <typename T, int M = 0>
typename std::enable_if<std::is_same<T,
std::complex<typename extractType<T>::subType>>::value,
MyArray<T,M> >::type
Random ()
{ return MyArray<T,M>{}; }
int main()
{
MyArray<int> i = Random<int>();
MyArray<double> d = Random<double>();
MyArray<std::complex<float>> c = Random<std::complex<float>>();
}
-- 编辑 2 --
根据 OP 改进修改的解决方案和示例(直接使用 extractType<T>::subType
而不是使用默认类型名称)。
只需将新功能基于您已有的功能即可:
template <>
auto Random<std::complex<double> >()
{
return std::complex<double>{Random<double>(), Random<double>()};
}
由于函数模板的部分特化是不允许的,你不能在这里完全通用并使用
template <typename T>
auto Random<std::complex<T> >() { ... } //error: partial specialization not allowed
您可以通过重载或使用带有静态成员函数的 class(可以部分特化)来解决这个问题。
通过函数参数推导,可以提取基础类型:
//overload for templates i.e. std::complex
template <class R, template <class...> class T>
R underlying_t_f(T<R>);
//overload for non template types
template < class T>
T underlying_t_f(T);
template < class T>
using underlying_t = decltype(underlying_t_f(T()));
然后在您的代码中将 T
替换为 underlying_t<T>
:
Online Demo
我有一个函数可以为我的数组生成随机数。我为浮点数和整数创建了两个重载,如下所示:
template <typename T, int M = 0>
typename std::enable_if<std::is_floating_point<T>::value && std::is_scalar<T>::value,MyArray<T,M> >::type
Random()
{
//...
}
template <typename T, int M = 0>
typename std::enable_if<std::is_integral<T>::value && std::is_scalar<T>::value, MyArray<T,M> >::type
Random()
{
//...
}
可以通过以下方式调用这些函数:
MyArray<int> i = Random<int>();
MyArray<double> d = Random<double>();
我想实现相同但使用 std::complex<T>
,其中 T
可以是任何浮点类型(最初 double 和 float 就足够了)。我希望能够做到这一点:
//This is what I'm trying to achieve
MyArray<std::complex<double> > = Random<std::complex<double>>();
MyArray<std::complex<float > > = Random<std::complex<float >>();
我无法完全做到这一点,但能够做到:
Random<std::complex,double>()
使用模板模板参数,这不是我要找的。
如何让 <std::complex<double>>
(或浮动)的重载工作?
使用标签分派 select 您想要的重载。此代码需要 C++14,但可以很容易地使其与 C++11 一起使用。但是你会失去可读性(重复的函数体,没有enable_if_t
)
首先,定义标签:
struct integral_tag{};
struct floating_point_tag{};
struct complex_tag{};
struct error_tag{};
一些辅助模板(标签select离子,complex
检测):
namespace detail
{
template<typename T> struct is_complex : false_type {};
template<typename T> struct is_complex<complex<T>> : true_type {};
template<typename T, typename = void>
struct select { using type = error_tag; };
template<typename T>
struct select<T, enable_if_t<is_integral<T>::value>>{
using type = integral_tag;
};
template<typename T>
struct select<T, enable_if_t<is_floating_point<T>::value>>{
using type = floating_point_tag;
};
template<typename T>
struct select<T, enable_if_t<is_complex<T>::value>>{
using type = complex_tag;
};
}
并且每个重载+默认一个到select他们:
template<typename T>
using random_tag = typename detail::select<T>::type;
template<typename T>
auto Random(floating_point_tag){
return T{};
}
template<typename T>
auto Random(integral_tag){
return T{};
}
template<typename T>
auto Random(complex_tag){
return T{typename T::value_type{}, typename T::value_type{}+1};
}
template<typename T>
auto Random()
{
return Random<T>(random_tag<T>{});
}
然后你就可以使用它们了:
int main()
{
cout << Random<int>() << endl;
cout << Random<float>() << endl;
cout << Random<complex<double>>() << endl;
}
我想创建一个提取器助手(例如,从 std::complex<float>
中提取 float
)作为
template <typename T>
struct extractType;
template <template <typename ...> class C, typename D>
struct extractType<C<D>>
{ using subType = D; };
你可以用它写
template <typename T, int M = 0>
typename std::enable_if<std::is_same<T, std::complex<
typename extractType<T>::subType>>::value
&& std::is_floating_point<typename extractType<T>::subType>::value
&& std::is_scalar<typename extractType<T>::subType>::value,
MyArray<T,M> >::type
Random ()
{ return MyArray<T,M>{}; }
或者干脆
template <typename T, int M = 0>
typename std::enable_if<std::is_same<T,
std::complex<typename extractType<T>::subType>>::value,
MyArray<T,M> >::type
Random ()
{ return MyArray<T,M>{}; }
如果你能明显地认为 std::complex
的模板参数是浮动的和标量的。
--- 编辑 ---
添加了一个完整的示例(好吧...带有错误 MyArray
)
#include <array>
#include <complex>
#include <type_traits>
template <typename T, int M = 0>
using MyArray = std::array<T, 10U>;
template <typename T>
struct extractType;
template <template <typename ...> class C, typename D>
struct extractType<C<D>>
{ using subType = D; };
template <typename T, int M = 0>
typename std::enable_if<std::is_floating_point<T>::value && std::is_scalar<T>::value,MyArray<T,M> >::type
Random ()
{ return MyArray<T,M>{}; }
template <typename T, int M = 0>
typename std::enable_if<std::is_integral<T>::value && std::is_scalar<T>::value, MyArray<T,M> >::type
Random ()
{ return MyArray<T,M>{}; }
template <typename T, int M = 0>
typename std::enable_if<std::is_same<T,
std::complex<typename extractType<T>::subType>>::value,
MyArray<T,M> >::type
Random ()
{ return MyArray<T,M>{}; }
int main()
{
MyArray<int> i = Random<int>();
MyArray<double> d = Random<double>();
MyArray<std::complex<float>> c = Random<std::complex<float>>();
}
-- 编辑 2 --
根据 OP 改进修改的解决方案和示例(直接使用 extractType<T>::subType
而不是使用默认类型名称)。
只需将新功能基于您已有的功能即可:
template <>
auto Random<std::complex<double> >()
{
return std::complex<double>{Random<double>(), Random<double>()};
}
由于函数模板的部分特化是不允许的,你不能在这里完全通用并使用
template <typename T>
auto Random<std::complex<T> >() { ... } //error: partial specialization not allowed
您可以通过重载或使用带有静态成员函数的 class(可以部分特化)来解决这个问题。
通过函数参数推导,可以提取基础类型:
//overload for templates i.e. std::complex
template <class R, template <class...> class T>
R underlying_t_f(T<R>);
//overload for non template types
template < class T>
T underlying_t_f(T);
template < class T>
using underlying_t = decltype(underlying_t_f(T()));
然后在您的代码中将 T
替换为 underlying_t<T>
:
Online Demo