具有特征参数的模板特化函数

时间:2017-12-24 17:47:25

标签: c++ c++11 templates eigen sfinae

我正在尝试使用特征类型的模板特化来编写一些函数,遵循以下问题: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!

我做错了什么?如何为具有特征矩阵和向量的函数编写模板特化?

2 个答案:

答案 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,您应该通过classstruct;

之类的东西
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添加的每种模板类型执行相同的操作。