特征:基类的模板特化中的类型演绎
Eigen: type deduction in template specialization of base-class
我尝试写一个c++模板类,它应该能够通过相同的接口处理"简单"类型和"Eigen::MatrixBase"类类型。我设法用两种不同的简单类型获得想要的行为,但很难将特征语法压缩到我的最小示例中……也许有人能给我点建议?
环顾四周,这接近我想要的——没有Eigen。这看起来也很相似。
#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
最后一个带有特征元素的代码块无法编译。我更迷失在如何解决这个问题的大方向上,具体的语法对我来说不是很清楚。使用这个头文件将无法在您的通用的minimal-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
对于任何类型Derived
,类型Eigen::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
技巧可以设置一个类模板专门化,它接受所有类型,并且只接受满足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
,要么定义并使用自己的:
template <bool Check, typename T = void>
struct enable_if {};
template <typename T>
struct enable_if<true, T> {
typedef T type;
};
相关文章:
- 类型演绎 C++ 标准和自动
- λ类型演绎失败
- decltype(auto) 类型演绎:返回 x 与返回 (x)
- 使用decltype的动态多态类型演绎
- 普遍类型演绎scott-meyers
- c++ 11使用std::函数进行类型演绎
- 使用通用引用时进行类型演绎
- c++如何在无法进行类型演绎时调用模板化构造函数
- c#泛型中的类型演绎类似于c++模板
- 类型演绎不适用于std::function
- 为什么decltype返回类型在递归模板中失败,而返回类型演绎却工作得很好?
- 表达式模板中的按引用捕获可以与类型演绎共存
- 类型演绎模板函数c++
- 模板,类型演绎不足
- 括号初始化列表和函数模板类型演绎顺序
- 类型演绎的重载赋值操作符
- 静态方法中派生类的类型演绎
- 在类型演绎之后,函数模板中的替换顺序是否有任何保证
- 返回类型演绎是否可能
- c++ 14中赋值时的返回类型演绎