Eigen:基类模板特化中的类型推导 [英] Eigen: type deduction in template specialization of base-class

查看:258
本文介绍了Eigen:基类模板特化中的类型推导的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试编写一个C ++模板类,它应该能够通过相同的接口处理简单类型和类似Eigen :: MatrixBase的类型。我设法通过两种不同的简单类型获得所需的行为,但很难将Eigen语法压缩到我的最小示例中...也许有人可以给我一个建议?

I trying do write a C++ template-class which should be able to deal with "simple" types and with "Eigen::MatrixBase"-like types via the same interface. I manage to get thie desired behavior with two different simple types, but struggle to squeeze the Eigen-syntax into my minimal-example... Maybe someone can give me an advice?

环顾四周时,这个来了接近我想要的 - 没有Eigen。 看起来也很相似。

While looking around, this comes close to what i wanna have -- without Eigen. This looks similar as well.

#ifndef __MINIMAL_H__
#define __MINIMAL_H__

#include <Eigen/Core>

// base-class defining and interface + common functions
// child-classes with possible overloads. does not work to
// define basic eigen-types as template specialization parameter

template<typename T>
class MinimalBase
{
    public:
        MinimalBase(const T& val)
            :val(val){};
        T val;
        // pure virtual interface
        virtual void setZero() = 0;
        // the common functionality
        void increase() { val = val*6; };
        void decrease() { val = val/7; };
};


// again pure virtual, so that the compiler will not instantiate this when
// trying to deduce the correct template specialization
template<typename T>
class Minimal : public MinimalBase<T>
{
    public:
        Minimal(const T& val)
            :MinimalBase<T>(val){};
        virtual void setZero() = 0;
        // the rest of the common functionality is inherited from MinimalBase
};

// one spezialization for "int"
template<>
class Minimal<int> : public MinimalBase<int>
{
    public:
        Minimal()
            :MinimalBase<int>(4){};
        virtual void setZero() { val = 0; };
};

// this one is actually shorter...
template<>
class Minimal<short> : public MinimalBase<short>
{
    public:
        Minimal()
            :MinimalBase<short>(1){};
        virtual void setZero() { val = 0; };
        void increase() { val = val*3; };
};

// and the eigen-one (at best limited to vector-like matrices)... how to do this?
template<class Derived>
class Minimal<Eigen::MatrixBase<Derived> > : public MinimalBase<Eigen::MatrixBase<Derived> >
{
        public:
        Minimal<Eigen::MatrixBase<Derived> >()
            :MinimalBase<Eigen::MatrixBase<Derived> >(Eigen::MatrixBase<Derived>::Zero()){};
        virtual void setZero() { this->val.setZero(); };
};
#endif

最后一个具有Eigen内容的块无法编译。我在一般方向上更迷失如何解决这个问题,具体的语法对我来说并不清楚。使用此标题,以下行将无法在您的通用minimal-example-main-cpp中编译(缺少Eigen-stuff):

The last block, with the Eigen stuff, does not compile. I'm more lost in the general direction how to solve this, the specific syntax is not clear to me. Using this header the following lines will not compile in your generic minimal-example-main-cpp (short of the Eigen-stuff):

Minimal<int>A;
Minimal<short>B;
// this does not work:
Minimal<Eigen::Vector2f>C;

std::cerr << "before: " << A.val << " " << B.val << "\n";
A.increase();
A.decrease();
B.increase();
B.setZero()
std::cerr << "after: " << A.val << " " << B.val << "\n";

编译器错误消息如下所示:

The Compiler error message looks like this:

/home/joe/test/test.cpp: In function ‘int main()’:
/home/joe/test/test.cpp:36:29: error: no matching function for call to ‘Minimal<Eigen::Matrix<float, 2, 1> >::Minimal()’
     Minimal<Eigen::Vector2f>C;
                             ^
/home/joe/test/test.cpp:36:29: note: candidates are:
In file included from /home/joe/test/test.cpp:7:0:
/home/joe/test/minimal.h:26:9: note: Minimal<T>::Minimal(const T&) [with T = Eigen::Matrix<float, 2, 1>]
         Minimal(const T& val)
         ^
/home/joe/test/minimal.h:26:9: note:   candidate expects 1 argument, 0 provided
/home/joe/test/minimal.h:23:7: note: Minimal<Eigen::Matrix<float, 2, 1> >::Minimal(const Minimal<Eigen::Matrix<float, 2, 1> >&)
 class Minimal : public MinimalBase<T>
       ^
/home/joe/test/minimal.h:23:7: note:   candidate expects 1 argument, 0 provided
/home/joe/test/test.cpp:36:29: error: cannot declare variable ‘C’ to be of abstract type ‘Minimal<Eigen::Matrix<float, 2, 1> >’
     Minimal<Eigen::Vector2f>C;
                             ^
In file included from /home/joe/test/test.cpp:7:0:
/home/joe/test/minimal.h:23:7: note:   because the following virtual functions are pure within ‘Minimal<Eigen::Matrix<float, 2, 1> >’:
 class Minimal : public MinimalBase<T>
       ^
/home/joe/test/minimal.h:29:22: note:       void Minimal<T>::setZero() [with T = Eigen::Matrix<float, 2, 1>]
         virtual void setZero() = 0;
                      ^

编辑:最终的最小示例演示终于找到了 github

The resulting minimal-example demonstration finally found its way to github

推荐答案

任何类型的 Eigen :: Vector2f 类型不等于 Eigen :: MatrixBase< Derived> 衍生。它继承了 Eigen :: MatrixBase< Eigen :: Vector2f> ,但这对模板专业化匹配来说还不够好。

The type Eigen::Vector2f is not equal to Eigen::MatrixBase<Derived> for any type Derived. It inherits Eigen::MatrixBase<Eigen::Vector2f>, but that's not good enough for template specialization matching.

首先,让我们定义一个类型特征,它确定一个类型是否是一个特征矩阵。在C ++ 11中:

First, let's define a "type trait" that determines whether a type is an Eigen matrix. In C++11:

#include <type_traits>

namespace is_eigen_matrix_detail {
    // These functions are never defined.
    template <typename T>
    std::true_type test(const Eigen::MatrixBase<T>*);
    std::false_type test(...);
}
template <typename T>
struct is_eigen_matrix
    : public decltype(is_eigen_matrix_detail::test(std::declval<T*>()))
{};

或者在C ++ 03中:

Or in C++03:

namespace is_eigen_matrix_detail {
    typedef char yes_type[2];
    typedef char no_type[1];
    template <typename T>
    yes_type test(const Eigen::MatrixBase<T>*);
    no_type test(...);
}
template <typename T>
struct is_eigen_matrix {
    static const bool value =
        (sizeof(is_eigen_matrix_detail::test(static_cast<T*>(0))) ==
         sizeof(is_eigen_matrix_detail::yes_type));
};

然后,可以设置标准的 enable_if 技巧一个类模板特化,它接受所有类型,只接受那些满足特征的类型。

Then, a standard enable_if trick can set up a class template specialization that accepts all types and only those types that satisfy the trait.

// Don't bother to define the primary template, and only your
// specializations can ever be used.
template <typename T, typename Enable = void>
class Minimal;

// When not using enable_if tricks, ignore the Enable parameter.
template<>
class Minimal<int> : public MinimalBase<int>
{
    // Just as before.
};

// This specialization only exists when T is or inherits an Eigen::MatrixBase
// specialization.
template <typename T>
class Minimal<T, typename std::enable_if<is_eigen_matrix<T>::value>::type>
    : public MinimalBase<T>
{
public:
    Minimal() : MinimalBase<T>(T::Zero()) {}
    virtual void setZero() { this->val.setZero(); }
};

std :: enable_if 是C ++ 11。在C ++ 03中,要么替换 boost :: enable_if ,要么只定义并使用自己的:

std::enable_if is C++11. In C++03, either substitute boost::enable_if or just define and use your own:

template <bool Check, typename T = void>
struct enable_if {};
template <typename T>
struct enable_if<true, T> {
    typedef T type;
};

这篇关于Eigen:基类模板特化中的类型推导的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆