繁体   English   中英

类型组的模板化类的成员专业化?

[英]Member specialization for a templated class for groups of types?

我有一个矩阵类,我想针对不同的矩阵类型(int,float,double)以不同的方式将矩阵打印到终端。 我想实现这一目标:

  • 如果矩阵类型为int ,则使用printf("%d ",matrix[i][j])打印矩阵
  • 如果矩阵类型为floatdouble ,则使用printf("%.3f ",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 float型矩阵都有一个通用的print()函数(不想复制同一件事两次)。 最简单的方法是什么? 谢谢!

作为建议的模板化解决方案的替代方案,使用了旧的良好函数重载:

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);
    }

所要求的问题是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实施

然后声明使用它们的函数模板:

template<typename T>
void print_matrix(detail::int_tag, T&&) {
    cout << __PRETTY_FUNCTION__ << endl;
}

template<typename T>
void print_matrix(detail::float_tag, T&&) {
    cout << __PRETTY_FUNCTION__ << endl;
}

template<typename T>
void print_matrix(detail::error_tag, T&&) {
    cout << __PRETTY_FUNCTION__ << endl;
}

并致电:

template <class T>
class Matrix2D {
private:
    std::vector< std::vector<T> > matrix;
public:

    void print() const {
        print_matrix(detail::tag<T>{}, *this);
    }
};

这是简单类型列表版本的实时示例。

您可以使用enable_if键入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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM