【问题标题】:C++ partial template specialization issueC ++部分模板专业化问题
【发布时间】:2020-06-06 11:11:18
【问题描述】:

给定一个矩阵类

using index_t = int;
template<index_t M, index_t N, typename S>
struct mat {
    // matrix implementation
};

我希望有一种通用方法来获取给定类型T 的 elementCount,该方法适用于矩阵和标量。例如,我想能够做到这一点:

dimensionality<mat<1,2,double>>(); // returns 2
dimensionality<mat<2,2,float>>(); // returns 4
dimensionality<double>(); // returns 1

或者可能是这样的:

attributes<mat<1,2,double>>::dimensionality; // returns 2
attributes<mat<2,2,float>>::dimensionality; // returns 4
attributes<double>::dimensionality; // returns 1

我的尝试:

我尝试执行以下操作(认为我部分专注于 struct attributes):

template<typename T>
struct attributes {};

template<typename S, typename = std::enable_if_t<std::is_arithmetic<S>::value>>
struct attributes<S> {                                        // <---  compiler error on this line
    static constexpr index_t dimensionality = 1;
};

template<index_t M, index_t N, typename S>
struct attributes<mat<M, N, S>> {
    static constexpr index_t dimensionality = M * N;
};

但我在指示的行上收到编译器错误。你能帮助我吗(或者通过提出更好的方法,或者理解我做错了什么)?

【问题讨论】:

    标签: c++ templates c++14 template-specialization


    【解决方案1】:

    首先,特化不能有比主模板更多的模板参数,但是您的代码将typename = std::enable_if_t 用于算术案例。

    其次,为了使这个std::enable_if_t 工作,它需要产生一些使专业化比主模板更专业的东西,而不仅仅是有效。为此,您可以使用void_t 技巧:

    template <typename T, typename = void>
    struct attributes {};
    
    template <typename S>
    struct attributes<S, std::enable_if_t<std::is_arithmetic<S>::value>> {
        static constexpr index_t dimensionality = 1;
    };
    

    这也意味着矩阵的特化也应该包括这个void参数:

    template <index_t M, index_t N, typename S>
    struct attributes<mat<M, N, S>, void> {
        static constexpr index_t dimensionality = M * N;
    };
    

    DEMO


    但是,您的特征可以缩短为:

    template <typename T>
    struct attributes {
        static_assert(std::is_arithmetic<T>::value, "T must be arithmetic or mat");
        static constexpr index_t dimensionality = 1;
    };
    
    template <index_t M, index_t N, typename S>
    struct attributes<mat<M, N, S>> {
        static constexpr index_t dimensionality = M * N;
    };
    

    DEMO 2

    也就是说,当没有专业化匹配时,只考虑主模板中的算术类型。

    【讨论】:

      【解决方案2】:

      您可以添加另一个默认类型为void 的模板参数,然后在算术类型的部分特化中指定std::enable_if 作为相应的模板参数。 (并调整mat 的部分特化。)

      template<typename T, typename = void>
      struct attributes {};
      
      template<typename S>
      struct attributes<S, std::enable_if_t<std::is_arithmetic<S>::value>> { 
          static constexpr index_t dimensionality = 1;
      };
      
      template<index_t M, index_t N, typename S>
      struct attributes<mat<M, N, S>, void> {
          static constexpr index_t dimensionality = M * N;
      };
      

      LIVE

      【讨论】:

        【解决方案3】:

        包装基于特征的静态常量:std::integral_constant

        您可能想利用&lt;type_traits&gt; 中的std::integral_constant 来实现您的特征,

        [...] std::integral_constant 包装指定类型的静态常量。它是 C++ 类型特征的基类。

        以及提供一个辅助变量模板dimensionality_v 以方便使用:

        #include <type_traits>
        
        // Default dimensionality 0.
        template <class T, typename = void>
        struct dimensionality : std::integral_constant<index_t, 0> {};
        
        template <typename S>
        struct dimensionality<S, std::enable_if_t<std::is_arithmetic_v<S>>>
            : std::integral_constant<index_t, 1> {};
        
        template <index_t M, index_t N, typename S>
        struct dimensionality<mat<M, N, S>> : std::integral_constant<index_t, M * N> {};
        
        template <class T>
        inline constexpr index_t dimensionality_v = dimensionality<T>::value;
        

        DEMO.

        或者,如果您不想为既不满足 std::is_arithmetic_v 也不等于 mat 的类型允许默认维度:

        template <class T, typename = void>
        struct dimensionality {};
        
        template <typename S>
        struct dimensionality<S, std::enable_if_t<std::is_arithmetic_v<S>>>
            : std::integral_constant<index_t, 1> {};
        
        template <index_t M, index_t N, typename S>
        struct dimensionality<mat<M, N, S>> : std::integral_constant<index_t, M * N> {};
        
        template <class T>
        inline constexpr index_t dimensionality_v = dimensionality<T>::value;
        

        DEMO.

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多