依赖于其他模板参数的模板参数

Template parameters that depend on other template parameters?

本文关键字:参数 其他 依赖于      更新时间:2023-10-16

我发现了一些类似的问题(例如这个(,但没有一个真正回答我的问题。请考虑以下代码片段:

template<unsigned int rows, unsigned int cols,typename arrtype>
class Variance
{
   double f(const arrtype &);
};
template<unsigned int rows, unsigned int cols>
double Variance<rows,cols,Eigen::Matrix<double,rows,cols>>
    ::f(const Eigen::Array<double,rows,cols> & M) 
{
  //do stuff
}

正如您在专业化中看到的那样,arrtype的类型将取决于 rowscols .上面的代码导致编译器错误 (g++ 5.4.0(:

invalid use of incomplete type ‘class Variance<rows, cols, Eigen::Matrix<double, rows, cols> >

我已经尝试在模板声明中typename arrtype<rows, cols>,但随后它抱怨arrtype不是一种类型,这是有道理的。

使用依赖于其他模板化类型的模板化类型的正确方法是什么?

这是代码的简化版本:

template<size_t rows, size_t cols> struct Foo {   double foo(); };
template<size_t rows> double Foo<rows,3>::f() { return 3;}

您收到的错误:

error: invalid use of incomplete type ‘struct Foo<rows, 3ul>’
double Foo<rows,3>::f() { return 3;}

问题不在于您的某个模板参数依赖于其他参数,而是您无法在不部分专用化类的情况下部分专用化成员。

这有效:

template<size_t rows, size_t cols> struct Foo {   double foo(); };
template<size_t rows> struct Foo<rows,3> { double f() { return 3;}  };

部分类专用化的替代方法(如 user463035818 的答案((或尝试完全专用化函数(是一种称为标记调度的技术。

执行此操作的方法是创建要调度到的重载帮助程序函数,并允许基于参数参数接管正常重载。

下面我将展示如何专注于Eigen::Array<double, rows, cols>

template<unsigned int rows, unsigned int cols,typename arrtype>
class Variance
{
public:
    double f(const arrtype& arg)
    {
        return f_impl(arg, tag<arrtype>{});
    }
private:
    template<class... T>
    struct tag{};
    template<class... T>
    double f_impl(const arrtype&, tag<T...>){
        std::cout << "catch-all functionn";
        return 42.0;
    }
    double f_impl(const arrtype&, tag<Eigen::Array<double, rows, cols>>){
        std::cout << "specialization for Eigen::Array<double, rows, cols>n";
        return 1337.0;
    }
};

现在你可以这样称呼它:

Variance<1, 1, int> non_specialized;
non_specialized.f(int{}); // prints "catch-all function"
Variance<1, 1, Eigen::Array<double, 1, 1>> specialized;
specialized.f(Eigen::Array<double, 1, 1>{}); // prints "specialization for Eigen::Array<double, rows, cols>"

演示


当您想要避免复制粘贴基本模板类和专用类的几乎相同的函数,或者将所有内容放入某个公共基库并使用多态性时,标记调度非常有用。