【问题标题】:Create transpose matrix function based on template C++基于模板C++创建转置矩阵函数
【发布时间】:2013-09-17 11:09:17
【问题描述】:

我正在尝试使用此 amazing guide 创建我的第一个模板,但遇到了我不知道如何处理多个嵌套参数的问题:

我原来创建的函数是这样实现的:

QVector< QVector<double> > transpose(QVector< QVector<double> > &matrix)
{
    int pre_numcols = matrix.size();
    int pre_numrows = matrix[0].size();
    QVector< QVector<double> > transposed(pre_numrows);
    QVector<double> newcols(pre_numcols);
    qFill(newcols.begin(), newcols.end(), 0.0);
    qFill(transposed.begin(), transposed.end(), newcols);
    qDebug()<<transposed.size();
    qDebug()<<transposed[0].size();
    for (int i = 0; i < pre_numcols; ++i)
    {
        for (int j = 0; j < pre_numrows; ++j)
        {
            transposed[j][i] = matrix[i][j];
        }
    }
    return transposed;
}

考虑到我只是重新洗牌,很多类型都是可能的。

QVector 可以替换为std::vectordouble 甚至可以替换为string

我已经走到这一步了:

template<class T>
T transpose(T &matrix)
{
    int pre_numcols = matrix.size();
    int pre_numrows = matrix[0].size();
    T transposed(pre_numrows);
    QVector<double> newcols(pre_numcols);  // How to do this one?

如果我将T 读作“container holding container holding some small type”,我如何声明newcols 变量,因为它是一个子集?

注意:稍后我将编辑qFill() 部分以适应其他情况,例如std::

【问题讨论】:

  • C++11 适合你吗?
  • @nijansen 是的,这是一个选项。

标签: c++ function templates transpose


【解决方案1】:

您可以使用模板作为模板参数:

template <
    template <typename> class Container,
    typename ValueType
>
void foo(Container<ValueType> const & c);

所以你的模板会变成:

template <
    template <typename> class Container,
    typename ValueType
>
Container< Container<ValueType> > transpose(Container< Container<ValueType> > & matrix)
{
    int pre_numcols = matrix.size();
    int pre_numrows = matrix[0].size();
    Container< Container<ValueType> > transposed(pre_numrows);
    Container<ValueType> newcols(pre_numcols);
    // ...
    return transposed;
}

如果它像那样工作,那就太好了。但是,与往常一样,新的问题出现了! std::vector 不是 template &lt;typename T&gt; class vector 而是

template <
    typename T,
    typename Allocator = allocator<T>
>
class vector

所以我们必须将函数更改为

template <
    template <typename, typename> class C,
    typename T,
    template <typename> class A = std::allocator,
    typename InnerType = C< T, A<T> >,
    typename OuterType = C< InnerType, A<InnerType> >
>
OuterType transpose(OuterType & matrix)
{
    int pre_numcols = matrix.size();
    int pre_numrows = matrix[0].size();
    OuterType transposed(pre_numrows);
    InnerType newcols(pre_numcols);
    // ...
    return transposed;
}

这不太整洁,我不确​​定 Qt 容器是否兼容。

既然你说 C++11 可以为你使用,你可以使用第一个函数(使用 template &lt;typename&gt; class Container)并为标准容器使用模板别名:

template <typename T> using vector = std::vector<T, std::allocator<T>>;
vector<vector<int>> v;
auto vprime = transpose<vector>(v);

这是另一种使用辅助模板元函数的可能解决方案,我认为它比以前的更干净:

namespace
{
    template <typename T> struct get_inner_i {};

    template <template <typename> class T, typename Inner> 
    struct get_inner_i<T<Inner>> { typedef Inner type; };

    template <
        template <typename, typename> class T, 
        typename Inner,
        template <typename> class Allocator
    > struct get_inner_i<T<Inner, Allocator<Inner>>> { typedef Inner type; };

    template <typename T> using get_inner = typename get_inner_i<T>::type;
}

template <typename MatrixType>
MatrixType transpose(MatrixType const & matrix)
{
    auto const nrows = matrix.size();
    auto const ncols = nrows > 0 ? matrix[0].size() : 0;

    MatrixType transposed(ncols, get_inner<MatrixType>(nrows));
    for(auto k = 0; k < nrows; ++k)
        for(auto j = 0; j < ncols; ++j)
            transposed[j][k] = matrix[k][j];

    return transposed;
}

为什么这个更冗长的解决方案更胜一筹?这不是我们必须编写多少代码,而是我们的功能对用户来说有多简单和直观。在这个版本中,我们再次将 T 作为模板参数,因此不需要显式指定函数的模板参数。

此外,我们的元函数可以推断它是否是带有自定义分配器参数的容器,并且用户不必执行上面提到的using模板别名技巧。


这是另一个解决方案,再次优于以前的解决方案,它使用std::begin 来确定容器的值类型,而不考虑其模板参数,甚至是否是模板,只要它提供@987654334 @ 和 end 迭代器,或者是 C 风格的数组:

namespace
{
    template <typename Container>
    struct value_type_i
    {
        typedef typename std::decay<
            decltype(*std::begin(std::declval<
                Container const &
            >()))
        >::type type;
    };

    template <typename Container>
    using value_type = typename value_type_i<Container>::type;
}

template <typename MatrixType>
MatrixType transpose(MatrixType const & matrix)
{
    auto const nrows = matrix.size();
    auto const ncols = nrows > 0 ? matrix[0].size() : 0;

    MatrixType transposed(ncols, value_type<MatrixType>(nrows));
    for(auto k = 0; k < nrows; ++k)
        for(auto j = 0; j < ncols; ++j)
            transposed[j][k] = matrix[k][j];

    return transposed;
}

你可以在这里看到它的工作原理:http://ideone.com/cCAyFD

【讨论】:

  • @Dualinity 又添加了一个解决方案,我想我现在继续:P
  • 哈,谢谢你的努力。您已经达到了今天的 &lt;&gt; 配额:P
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-19
  • 2020-10-06
  • 2017-08-21
  • 1970-01-01
  • 2021-11-16
  • 1970-01-01
相关资源
最近更新 更多