2014-03-29 73 views
3

我想寫一個C++模板類,它應該能夠通過相同的接口處理「簡單」類型和「Eigen :: MatrixBase」類型的類型。我設法用兩種不同的簡單類型來獲得期望的行爲,但是很難將特徵語法壓縮到我最小的例子中......也許有人可以給我一個建議?Eigen:基類的模板專業化中的類型推導

雖然環顧四周,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 

最後一塊,與特徵的東西,不編譯。我在大方向上更多地迷失了這個問題,具體的語法對我來說並不清楚。使用這個標題下面的行不會在通用最小,例如,主CPP編譯(短的本徵的東西):

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

+0

純虛擬函數對模板類型推演沒有影響。 – aschepler

+0

你得到了什麼編譯器錯誤? – aschepler

回答

6

對於任何類型DerivedEigen::Vector2f的類型不等於Eigen::MatrixBase<Derived>。它繼承Eigen::MatrixBase<Eigen::Vector2f>,但這不足以用於模板專門化匹配。

首先,讓我們定義一個「類型特徵」,它確定類型是否是特徵矩陣。在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; 
}; 
+0

非常感謝。奇蹟般有效!模板編程有點像VHDL中的硬件編程;-)不幸的是,C++ 11對我的目標來說是遙不可及的...... – user3474620

+0

爲什麼「this->」仍然需要? – user3474620

+0

Boost具有C++ 03兼容的'enable_if',或者編寫它很簡單。對於'this->'問題,請參閱http://isocpp.org/wiki/faq/templates#nondependent-name-lookup-members – aschepler