递归类型或依赖关系上下文太复杂

时间:2017-02-28 12:41:46

标签: c++ templates

很抱歉,如果以前出现这种情况,我花了一段时间寻找类似的问题,但我看不出有任何问题这个

我正在编写一些使用拉普拉斯扩展递归计算矩阵行列式的代码 - 这需要计算出小矩阵,我已经将其实现为一个类,其中包含对实际矩阵的引用并提供类似的函数(例如大小和运算符( ))返回次要矩阵的正确值。次要矩阵类需要能够接受基本矩阵类或另一个次要矩阵类,因此需要模板化,对于行列式函数也是如此。

但是,我的代码(在VS2017上编译)产生错误'C1202:递归类型或函数依赖关系上下文过于复杂'。以下是重现错误的最小示例:

#include <iostream>

template <typename T>
class A
{
public:
    typedef T type;

    A(T value) : value(value) {}
    type get_value() const { return value; }
private:
    T value;
};

template <typename T>
class B
{
public:
    typedef typename T::type type;

    B(const T& t) : t(t) {}
    type get_value() const { return t.get_value() - 1; }
private:
    const T& t;
};

template <typename T>
typename T::type foo(const T& t)
{
    if (t.get_value() == 0)
        return 0;
    else
        return t.get_value() + foo(B<T>(t));
}

int main()
{
    std::cout << foo(A<int>(5));
    std::cin.ignore();
}

(我认为如果编译它应该打印15)。

任何意见都会受到赞赏。

编辑:这是非最小代码(根据要求) - 取决于boost :: ublas库

#include <boost/numeric/ublas/matrix.hpp>
#include <iostream> 

template <typename Matrix>
class matrix_minor
{
public:
    typedef boost::numeric::ublas::matrix<double>::const_reference const_reference;
    typedef boost::numeric::ublas::matrix<double>::size_type size_type;

    matrix_minor(const Matrix& A, unsigned int i, unsigned int j) :
        A(A), i(i), j(j) {}

    size_type size1() const { return A.size1() - 1; }

    size_type size2() const { return A.size2() - 1; }
    const_reference operator () (size_type i_, size_type j_) const
    {
        return A(
                (i_ >= i ? i_ + 1 : i_),
                (j_ >= j ? j_ + 1 : j_)
                );
    }

private:
    const Matrix& A;
    unsigned int i, j;
};

template <typename Matrix>
double det(const Matrix& A)
{
    if (A.size1() != A.size2())
        throw "Matrix must be square";

    unsigned int n = A.size1(); //Size of the matrix

    //Early returns for special cases 
    if (n == 1)
        return A(0, 0);
    else if (n == 2)
        return A(0, 0) * A(1, 1) - A(1, 0) * A(0, 1);

    unsigned int i = 0; //Row over which to compute the determinant
    double d = 0; //Value of the determinant
    for (unsigned int j = 0; j < n; ++j) {
        d += (j % 2 == 0 ? 1 : -1) * A(i, j) * det(matrix_minor<Matrix>(A, i, j));
    }
    return d;
}

int main()
{
    boost::numeric::ublas::matrix<double> m(3, 3, 1);
    m(0, 0) = 2; 
    m(1, 1) = 3;
    //m = ( (2,1,1), (1,1,1), (1,1,1) )
    std::cout << det(m); //Should print 2
}

2 个答案:

答案 0 :(得分:4)

templates在编译时实例化。您的计算不在编译时,因此,编译器无法看到实例化的结束并实例化最大次数。

例如在gcc中,这将是:

In instantiation of ‘B<T>::B(const T&) [with T = B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<B<A<int> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >]’:
new.cpp:34:35:   recursively required from ‘typename T::type foo(const T&) [with T = B<A<int> >]’
new.cpp:34:35:   required from ‘typename T::type foo(const T&) [with T = A<int>]’
new.cpp:39:18:   required from here
new.cpp:22:27: fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)
     B(const T& t) : t(t) {}

模板递归可以这样完成:

template<int N>
constexpr int factorial()
{
   return N * factorial<N - 1>();
}

template<>
constexpr int factorial<0>()
{
   return 1;
}

这里编译器知道,N为零时有特定的动作,它会停止递归。

你的例子就是这样的。注意:使用C ++ 17 if constexpr

template <typename T, T N>
class A
{
public:
    typedef T type;
    static constexpr type value = N;

    static constexpr type get_value() { return value; }
};

template <typename T>
class B
{
public:
    typedef typename T::type type;

    static constexpr type get_value() { return T::get_value() - 1; }
};

template <typename T>
typename T::type foo()
{
    if constexpr(T::get_value() == 0)
        return 0;
    else
        return T::get_value() + foo<B<T>>();
}

Live

答案 1 :(得分:0)

正如您所发现的那样,您无法以递归方式构造具有运行时值的模板类型,因为模板实例化必须以某种方式停止。

另一个想法是将matrix_minor修改为不模板嵌套,但代价是更难实现。

template <typename Matrix>
class matrix_minor
{
public:
    typedef boost::numeric::ublas::matrix<double>::const_reference const_reference;
    typedef boost::numeric::ublas::matrix<double>::size_type size_type;

    matrix_minor(const Matrix& A, unsigned int i, unsigned int j) :
        A(A), is({i}), js({j}) {}

    matrix_minor(const matrix_minor<Matrix>& inner, unsigned int i, unsigned int j) :
        A(inner.A), is(inner.is), js(inner.js) { is.push_back(i); js.push_back(j); }

    size_type size1() const { return A.size1() - is.count(); }

    size_type size2() const { return A.size2() - js.count(); }
    const_reference operator () (size_type i_, size_type j_) const
    {
        // I think this is correct for nested matrix_minors
        for (size_type i : is)
        {
            i_ += i_ >= i;
        }
        for (size_type j : js)
        {
            j_ += j_ >= j;
        }
        return A(i_, j_);
    }

private:
    const Matrix& A;
    vector<unsigned int> is, js;
};