2016-10-10 101 views
4

我有一个矩阵类,我想打印到不同的矩阵类型(int,float,double)不同的矩阵到终端。我想实现这一点:如果矩阵类型,如果floatdouble,打印矩阵使用printf("%.3f ",matrix[i][j]) 成员专业化的模板类为组类?

  • 否则如果矩阵类型,如果int,打印矩阵使用printf("%d ",matrix[i][j])
    • ,抛出一个错误

    以下是我所拥有的相关部分:

    ... 
    
    template <class T> 
    class Matrix2D { 
    private: 
        std::vector< std::vector<T> > matrix; 
    public: 
        ... 
        void print() const; // print the whole matrix 
    } 
    
    ... 
    
    template <class T> 
    void Matrix2D<T>::print() const { 
        // throw an error 
    } 
    
    template <> 
    void Matrix2D<int>::print() const { 
        // print matrix using printf("%d ",matrix[i][j]) 
    } 
    
    template <> 
    void Matrix2D<float,double>::print() const { 
        // print matrix using printf("%.3f ",matrix[i][j]) 
    } 
    

    但使用Matrix2D<float,double>给我错误信息error: wrong number of template arguments (2, should be 1)。但是,我希望floatdouble型矩阵具有共同的print()函数(不希望两次复制相同的东西)。达到此目的最简单的方法是什么?谢谢!

  • 回答

    2

    只是作为一个替代方案提出的解决方案模板,使用旧的好函数重载:

    public: 
        void print() const 
        { 
         for (auto const& row : matrix) 
          for (auto const& v : row) 
           print(v); 
        } 
    
    private: 
        static void print(int val) 
        { 
         printf("%d ", val); 
        } 
    
        static void print(float val) 
        { 
         printf("%.3f", val); 
        } 
    
    +0

    这是我落得这样做吧。这是一个轻量级解决方案,避免了额外的库。我可以将大部分的显示功能写入一块,并调用此重载打印功能,从而最大限度地减少额外的代码写入。 –

    0

    你可以使用enable_iftype traits,不要做这样的事情:

    template<class T> class MyClass 
    { 
    public: 
        // this one will be created if the argument is of a floating point type, i.e. 
        // double or float 
        template<typename U = T> 
        typename std::enable_if<std::is_floating_point<U>::value, void>::type 
        print(U v) 
        { 
         std::cout << "float" << std::endl; 
        } 
    
        // this one will be created if the argument is of an integral type, i.e. 
        // bool, char, char16_t, char32_t, wchar_t, short, int, long, long long 
        template<typename U = T> 
        typename std::enable_if<std::is_integral<U>::value, void>::type 
        print(U v) 
        { 
         std::cout << "integer" << std::endl; 
        } 
    
    }; 
    
    
    int main() { 
        MyClass<int>c; 
        c.print(1); 
        c.print(1.f); 
    } 
    

    输出:

    integer 
    float 
    
    1

    了一个问题,问想Matrix2D<short>::print()抛出一个错误。为了达到这个目的,你可以使用标签调度。

    标签 - 简单

    天真的方法需要你专门标记为每种类型的直接。

    namespace detail 
    { 
    
    struct int_tag{}; 
    struct float_tag{}; 
    struct error_tag{}; 
    
    template<typename T> struct choose_tag { using type = error_tag; }; 
    
    template<> struct choose_tag<int> { using type = int_tag; }; 
    template<> struct choose_tag<double> { using type = float_tag; }; 
    template<> struct choose_tag<float> { using type = float_tag; }; 
    
    template<typename T> 
    using tag = typename choose_tag<T>::type; 
    
    } 
    

    标签 - 类型列表

    你可以用Boost.Hana(或其他MPL溶液)避免这种情况。首先,在名单确定检查的类型:

    template<typename T, typename... Us> 
    constexpr bool contains = 
         hana::any_of(hana::tuple_t<Us...>, hana::partial(hana::equal, hana::type_c<T>))(); 
    

    然后,只需enable_if这类型的标签:

    template<typename T, typename = std::void_t<>> 
    struct choose_tag 
    { using type = error_tag; }; 
    
    template<typename T> 
    struct choose_tag<T, enable_if_t<contains<T, int>>> 
    { using type = int_tag; }; 
    
    template<typename T> 
    struct choose_tag<T, enable_if_t<contains<T, double, float>>> 
    { using type = float_tag; }; 
    

    通用 - print实施

    然后声明使用这些函数模板:

    ​​

    and call:

    template <class T> 
    class Matrix2D { 
    private: 
        std::vector< std::vector<T> > matrix; 
    public: 
    
        void print() const { 
         print_matrix(detail::tag<T>{}, *this); 
        } 
    }; 
    

    下面是simpletype list版本的实时示例。