【问题标题】:Eigen: type deduction in template specialization of base-classEigen:基类模板特化中的类型推导
【发布时间】:2014-03-29 01:30:51
【问题描述】:

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

环顾四周,this 接近我想要的——没有 Eigen。 This 看起来也很相似。

#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 内容的最后一个块无法编译。我对如何解决这个问题的总体方向更加迷茫,具体的语法对我来说不是很清楚。使用此标头,以下行将不会在您的通用 minimum-example-main-cpp 中编译(缺少 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";

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

/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

【问题讨论】:

  • 纯虚函数对模板类型推导没有影响。
  • 你得到什么编译器错误?

标签: c++ templates inheritance eigen


【解决方案1】:

对于任何类型Derived,类型Eigen::Vector2f 都不等于Eigen::MatrixBase&lt;Derived&gt;。它继承了Eigen::MatrixBase&lt;Eigen::Vector2f&gt;,但这对于模板特化匹配来说还不够好。

首先,让我们定义一个“类型特征”来确定一个类型是否是一个特征矩阵。在 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 中:

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 技巧可以设置一个类模板特化,它接受所有类型并且只接受那些满足特征的类型。

// 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,要么只定义并使用你自己的:

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

【讨论】:

  • 非常感谢。奇迹般有效!模板编程有点像 VHDL 中的硬件编程 ;-) 遗憾的是,c++11 对我的目标来说是遥不可及的......
  • 为什么还需要“this->”?
  • Boost 有 C++03 兼容的enable_if,或者写一个很简单。对于this-&gt; 问题,请参阅isocpp.org/wiki/faq/templates#nondependent-name-lookup-members
  • 添加了 C++03 cmets。
  • 不错。必须将“typedef yes/no_type”更改为不同的非数组类型,如 int 和 char...?
猜你喜欢
  • 1970-01-01
  • 2019-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-01
  • 1970-01-01
相关资源
最近更新 更多