我正在尝试使用特征类型的模板特化来编写一些函数,遵循以下问题:Eigen: type deduction in template specialization of base-class
我写了这个:
#include <type_traits>
#include <Eigen/Core>
namespace isEigenPlainObjectBaseDetail {
template <typename T>
std::true_type test(const Eigen::PlainObjectBase<T>);
std::false_type test(...);
}
template <typename T>
struct isEigenPlainObjectBase :
public decltype(isEigenPlainObjectBaseDetail::test(std::declval<T>())) {};
template <typename T, typename Enable = void>
void foo(T& obj) {
std::cout << "Generic Called!\n";
}
template <typename T, typename std::enable_if<isEigenPlainObjectBase<T>::value>::type>
void foo(T& obj) {
std::cout << "Eigen Specialization Called!";
}
int main() {
Eigen::MatrixXd m;
Eigen::VectorXd v;
int i = 0;
foo(i);
foo(m);
foo(v);
return 0;
}
但每次都会调用泛型函数:
Generic Called!
Generic Called!
Generic Called!
我做错了什么?如何为具有特征矩阵和向量的函数编写模板特化?
答案 0 :(得分:0)
不确定这是唯一的问题(没有Eigen安装,所以我无法检查;对不起)但是......
你可以部分地专门化结构和类,而不是函数。
所以这段代码
template <typename T, typename Enable = void>
void foo(T& obj) {
std::cout << "Generic Called!\n";
}
template <typename T, typename std::enable_if<isEigenPlainObjectBase<T>::value>::type>
void foo(T& obj) {
std::cout << "Eigen Specialization Called!";
}
不起作用,我很惊讶编译。
编辑:正如Quentin指出的那样(谢谢!)第二个模板参数的第二个模板参数是非类型的;所以两个foo()
之间没有冲突,但第二个被排除,因为非类型模板参数的类型为void
。这是不允许的。
要使用SFINAE,您应该通过class
或struct
;
template <typename T, typename = void>
struct foo
{
static void func (T & obj)
{ std::cout << "Generic Called!\n"; }
};
template <typename T
struct foo<T, typename std::enable_if<isEigenPlainObjectBase<T>::value>::type>
{
static void func (T & obj)
{ std::cout << "Eigen Specialization Called!"; }
};
可以用作
foo<decltype(i)>::func(i);
foo<decltype(m)>::func(m);
foo<decltype(v)>::func(v);
也许您可以定义bar()
模板帮助函数
template <typename T>
void bar (T & t)
{ foo<T>::func(t); }
然后直接致电
bar(i);
bar(m);
bar(v);
或许使用标签调度更简单。
如果您定义了几个foo()
接收不同的附加参数
template <typename T>
void foo (T &, std::false_type const &)
{ std::cout << "Generic Called!\n" }
template <typename T>
void foo (T &, std::true_type const &)
{ std::cout << "Eigen Specialization Called!"; }
您应该能够选择具有foo()
辅助函数的正确bar()
template <typename T>
void bar (T & t)
{ foo(t, isEigenPlainObjectBase<T>{}); }
和以前一样,只需调用
bar(i);
bar(m);
bar(v);
[警告:未经测试]
答案 1 :(得分:0)
如果你只想为你传递的两种类型专门化一个函数,它可能比你想象的要简单得多。
当前代码:
template <typename T, typename Enable = void>
void foo(T& obj) {
std::cout << "Generic Called!\n";
}
template <typename T, typename std::enable_if<isEigenPlainObjectBase<T>::value>::type>
void foo(T& obj) {
std::cout << "Eigen Specialization Called!";
}
新守则:
template <typename T>
void foo(T& obj);
template <>
void foo(Eigen::MatrixXd& obj) {
std::cout << "Eigen Specialization Called!" << std::endl;
}
template <>
void foo(Eigen::VectorXd& obj) {
std::cout << "Eigen Specialization Called!" << std::endl;
}
template <typename T>
void foo(T& obj) {
std::cout << "Generic Called!" << std::endl;
}
注意,未编译为测试。
另一种方法是为感兴趣的类型添加特征,你会怎么做?
我建议的方式如下。 (注意未编译/测试)
template<typename T>
struct isEigenTrait;
//specializations for all of the eigen types you are interested in
template<>
struct isEigenTrait<Eigen::MatrixXd> {
typedef std::true_type value;
};
//...
template<typename T>
struct isEigenTrait {
typedef std::false_type value;
};
template<class T, std::enable_if_t<isEigenTrait<T>::value, true_type> = 0>
void foo(T& obj) {
std::cout << "Eigen Specialization Called!" << std::endl;
}
template<class T, std::enable_if_t<isEigenTrait<T>::value, false_type> = 0>
void foo(T& obj) {
std::cout << "Generic Called!" << std::endl;
}
从c ++引用修改的代码应该可以工作。
为了使所有的特征矩阵都在一个特征中,我相信以下内容应该有效。
//specializations for all of the eigen types you are interested in
template<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>
struct isEigenTrait< Eigen::Matrix<Scalar, RowsAtCompileTime, ColsAtCompileTime> > {
typedef std::true_type value;
};
您可能需要对希望isEigenTrait添加的每种模板类型执行相同的操作。