【问题标题】:Multiple variable template specializations with std::enable_if使用 std::enable_if 的多变量模板特化
【发布时间】:2018-12-30 23:42:44
【问题描述】:

我正在尝试用这些有效值简洁地定义一个变量模板:

// (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&lt;float&gt; 表示floats 的向量)。这可以通过 VecXX::value_type 或通过类型特征样式模板类 (VectorTraits&lt;VecXX&gt;::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>);

但我无法确定一个工作版本(以上失败,“重新定义const T huge&lt;T&gt;”)。最好的方法是什么?

【问题讨论】:

    标签: c++ c++14 sfinae enable-if variable-templates


    【解决方案1】:

    不完全是你问的,但我希望下面的例子可以告诉你如何使用 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;
    

    【讨论】:

    • 这可能是最好的,我想我可以添加另一个专业化 std::enable_if&lt;/*is vector*/&gt; 以将其限制为矢量类型。
    • @ZachB - 不确定你想要什么,但是......增加了专业化
    • 抱歉,我的意思是我可以使用std::enable_if&lt;/* is Vec4f or Vec8f or VecXX... */&gt; 添加专业化。我知道该怎么做,只是大声思考。谢谢!
    • 我已经(希望)澄清了问题并发布了到目前为止的具体解决方案,指出了剩余的缺陷,以防您有任何改进的想法。
    【解决方案2】:

    将@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&lt;uint32_t&gt;)仍会使用无意义的0 值进行编译。我宁愿他们不编译。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-13
      • 1970-01-01
      • 2019-08-30
      • 1970-01-01
      相关资源
      最近更新 更多