std::enable_if 的多变量模板特化
Multiple variable template specializations with std::enable_if
我试图用这些有效值简洁地定义一个变量模板:
// (template<typename T> constexpr T EXP = std::numeric_limits<T>::max_exponent / 2;)
// float and double scalar definitions:
const double huge = std::scalbn(1, EXP<double>);
const float huge = std::scalbn(1, EXP<float>);
// SIMD vector definitions:
const Vec8f huge = Vec8f(huge<float>); // vector of 8 floats
const Vec8d huge = Vec8d(huge<double>); // vector of 8 doubles
const Vec4f huge = Vec4f(huge<float>); // vector of 4 floats
// Integral types should fail to compile
VecXX 向量定义(SIMD 向量)需要使用相应的标量类型,如图所示(例如 huge<float>
用于 float
s 的向量)。这可以作为 VecXX::value_type
或通过类型特征样式模板 class (VectorTraits<VecXX>::value_type
).
获得
理想情况下,我想我会有这样的东西:
// Primary. What should go here? I want all other types to not compile
template<typename T, typename Enabler = void>
const T huge = T{ 0 };
// Scalar specialization for floating point types:
template<typename T>
const T huge<T> = std::enable_if_t<std::is_floating_point<T>::value, T>(std::scalbn(1, EXP<T>));
// Vector specialization, uses above declaration for corresponding FP type
template<typename T>
const T huge<T> = std::enable_if_t<VectorTraits<T>::is_vector, T>(huge<VectorTraits<T>::scalar_type>);
但我无法完全找出一个工作版本(以上失败 "redefinition of const T huge<T>
")。执行此操作的最佳方法是什么?
不完全是你问的,但我希望下面的例子能告诉你如何使用 SFINAE 来特化模板变量
template <typename T, typename = void>
constexpr T huge = T{0};
template <typename T>
constexpr T huge<T, std::enable_if_t<std::is_floating_point<T>{}>> = T{1};
template <typename T>
constexpr T huge<std::vector<T>> = T{2};
您可以通过
查看
std::cout << huge<int> << std::endl;
std::cout << huge<long> << std::endl;
std::cout << huge<float> << std::endl;
std::cout << huge<double> << std::endl;
std::cout << huge<long double> << std::endl;
std::cout << huge<std::vector<int>> << std::endl;
留下@max66 的答案作为认可的答案,但这是我最终得出的具体解决方案:
struct _VectorTraits { static constexpr bool is_vector = true; };
template<class T> struct VectorTraits : _VectorTraits { static constexpr bool is_vector = false; };
template<> struct VectorTraits<Vec4f> : _VectorTraits { typedef float value_type; };
template<> struct VectorTraits<Vec8f> : _VectorTraits { typedef float value_type; };
template<> struct VectorTraits<Vec4d> : _VectorTraits { typedef double value_type; };
template<typename T> using EnableIfFP = std::enable_if_t<std::is_floating_point<T>::value>;
template<typename T> using EnableIfVec = std::enable_if_t<VectorTraits<T>::is_vector>;
template<typename T> constexpr T EXP = std::numeric_limits<T>::max_exponent / 2;
// Actual variable template, finally:
template<typename T, typename Enabler = void> const T huge = T{ 0 };
template<typename T> const T huge<T, EnableIfFP<T> > = std::scalbn(1, EXP<T>);
template<typename T> const T huge<T, EnableIfVec<T> > = T{ huge<typename VectorTraits<T>::value_type> };
我认为这仍然可以改进:
- 很冗长。
T
在每个专精的左侧出现 4 次。
- 整数类型(例如
huge<uint32_t>
)仍然使用无意义的 0
值编译。我宁愿他们不编译。
我试图用这些有效值简洁地定义一个变量模板:
// (template<typename T> constexpr T EXP = std::numeric_limits<T>::max_exponent / 2;)
// float and double scalar definitions:
const double huge = std::scalbn(1, EXP<double>);
const float huge = std::scalbn(1, EXP<float>);
// SIMD vector definitions:
const Vec8f huge = Vec8f(huge<float>); // vector of 8 floats
const Vec8d huge = Vec8d(huge<double>); // vector of 8 doubles
const Vec4f huge = Vec4f(huge<float>); // vector of 4 floats
// Integral types should fail to compile
VecXX 向量定义(SIMD 向量)需要使用相应的标量类型,如图所示(例如 huge<float>
用于 float
s 的向量)。这可以作为 VecXX::value_type
或通过类型特征样式模板 class (VectorTraits<VecXX>::value_type
).
理想情况下,我想我会有这样的东西:
// Primary. What should go here? I want all other types to not compile
template<typename T, typename Enabler = void>
const T huge = T{ 0 };
// Scalar specialization for floating point types:
template<typename T>
const T huge<T> = std::enable_if_t<std::is_floating_point<T>::value, T>(std::scalbn(1, EXP<T>));
// Vector specialization, uses above declaration for corresponding FP type
template<typename T>
const T huge<T> = std::enable_if_t<VectorTraits<T>::is_vector, T>(huge<VectorTraits<T>::scalar_type>);
但我无法完全找出一个工作版本(以上失败 "redefinition of const T huge<T>
")。执行此操作的最佳方法是什么?
不完全是你问的,但我希望下面的例子能告诉你如何使用 SFINAE 来特化模板变量
template <typename T, typename = void>
constexpr T huge = T{0};
template <typename T>
constexpr T huge<T, std::enable_if_t<std::is_floating_point<T>{}>> = T{1};
template <typename T>
constexpr T huge<std::vector<T>> = T{2};
您可以通过
查看std::cout << huge<int> << std::endl;
std::cout << huge<long> << std::endl;
std::cout << huge<float> << std::endl;
std::cout << huge<double> << std::endl;
std::cout << huge<long double> << std::endl;
std::cout << huge<std::vector<int>> << std::endl;
留下@max66 的答案作为认可的答案,但这是我最终得出的具体解决方案:
struct _VectorTraits { static constexpr bool is_vector = true; };
template<class T> struct VectorTraits : _VectorTraits { static constexpr bool is_vector = false; };
template<> struct VectorTraits<Vec4f> : _VectorTraits { typedef float value_type; };
template<> struct VectorTraits<Vec8f> : _VectorTraits { typedef float value_type; };
template<> struct VectorTraits<Vec4d> : _VectorTraits { typedef double value_type; };
template<typename T> using EnableIfFP = std::enable_if_t<std::is_floating_point<T>::value>;
template<typename T> using EnableIfVec = std::enable_if_t<VectorTraits<T>::is_vector>;
template<typename T> constexpr T EXP = std::numeric_limits<T>::max_exponent / 2;
// Actual variable template, finally:
template<typename T, typename Enabler = void> const T huge = T{ 0 };
template<typename T> const T huge<T, EnableIfFP<T> > = std::scalbn(1, EXP<T>);
template<typename T> const T huge<T, EnableIfVec<T> > = T{ huge<typename VectorTraits<T>::value_type> };
我认为这仍然可以改进:
- 很冗长。
T
在每个专精的左侧出现 4 次。 - 整数类型(例如
huge<uint32_t>
)仍然使用无意义的0
值编译。我宁愿他们不编译。