我有一个为我的数组生成随机数的函数。我为浮点数和整数创建了两个重载,如下所示:
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>()
使用模板模板参数,这不是我正在寻找的。 p>
如何通过<std::complex<double>>
(或浮点数)来实现重载?
答案 0 :(得分:3)
使用标签分派选择所需的过载。这段代码需要C ++ 14,但它可以很容易地与C ++ 11一起使用。尽管如此(重复的函数体,没有enable_if_t
)
首先,定义标签:
struct integral_tag{};
struct floating_point_tag{};
struct complex_tag{};
struct error_tag{};
一些助手模板(标签选择,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;
};
}
和每个重载+默认选择它们:
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;
}
答案 1 :(得分:2)
我认为创建一个提取器帮助器(例如,从float
中提取std::complex<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
而不是使用默认类型名称。)
答案 2 :(得分:1)
只需将新功能基于您已有的功能:
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
您可以使用静态成员函数重载或使用类(可以部分专门化)来解决这个问题。
答案 3 :(得分:0)
使用函数参数推导可以提取基础类型:
//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