依赖于其他模板参数的模板参数?
Template parameters that depend on other template parameters?
我发现了一些类似的问题(例如 this),但其中none确实回答了我的问题。考虑这个代码片段:
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
将取决于 rows
和 cols
。上面的代码导致编译器错误 (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;}
问题不在于您的模板参数之一依赖于其他模板参数,而是您不能在不部分特化 class.
的情况下部分特化一个成员
这个有效:
template<size_t rows, size_t cols> struct Foo { double foo(); };
template<size_t rows> struct Foo<rows,3> { double f() { return 3;} };
像 那样的部分 class 专业化(或尝试完全专业化函数)的替代方法是一种称为 tagged dispatch 的技术。
你这样做的方法是创建重载的辅助函数来分派,并允许正常的重载基于参数参数接管。
下面我将展示如何专攻 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 function\n";
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>"
Demo
当您想避免为基本模板 class 和您的专用 class 复制粘贴几乎相同的函数,或者将所有内容放入一些公共基础并使用多态性时,标记分派非常有用.
我发现了一些类似的问题(例如 this),但其中none确实回答了我的问题。考虑这个代码片段:
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
将取决于 rows
和 cols
。上面的代码导致编译器错误 (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;}
问题不在于您的模板参数之一依赖于其他模板参数,而是您不能在不部分特化 class.
的情况下部分特化一个成员这个有效:
template<size_t rows, size_t cols> struct Foo { double foo(); };
template<size_t rows> struct Foo<rows,3> { double f() { return 3;} };
像
你这样做的方法是创建重载的辅助函数来分派,并允许正常的重载基于参数参数接管。
下面我将展示如何专攻 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 function\n";
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>"
Demo
当您想避免为基本模板 class 和您的专用 class 复制粘贴几乎相同的函数,或者将所有内容放入一些公共基础并使用多态性时,标记分派非常有用.