我希望这个问题不会过于复杂。我意识到元编程作用于类型而不是那些类型的对象;但是,我仍然试图通过1)从类中检索类型信息,然后2)对该类型信息的元函数来实现相同的结果。
我的情况解释如下,简化代码摘录:
我有一个矩阵模板类,我称之为Matrix_Base。有点类似于Eigen采用的方法,我允许矩阵大小的两种可能性 - 在编译时固定或在运行时固定。 Matrix_Base的简化声明是:
template <typename Type, uint32_t rows_ = 1, uint32_t cols_ = 1,>
class Matrix_Base{
/*
...
*/
};
运行时大小的矩阵由参数0表示。
检查矩阵的运行时与编译时大小相当简单(使用boost :: mpl):
typedef typename mpl::if_<
typename mpl::or_<
typename mpl::equal_to<
typename mpl::int_<rows_>::type,
mpl::int_<0>
>::type,
typename mpl::equal_to <
typename mpl::int_<cols_>::type,
mpl::int_<0>
>
>::type,
mpl::true_,
mpl::false_
>::type runtime_size_type;
这已经过测试并且运行正常。我的麻烦从这里开始......
目前,我正在以下列方式使用上述boost :: mpl代码:
namespace internal {
template <uint32_t rows = 1, uint32_t cols_ = 1>
struct Runtime_Size_Helper {
typedef typename mpl::if_<
// REST OF THE BOOST::MPL code here //
>::type runtime_size_t
bool value() { return runtime_size_t::value;}
};
} // namespace
template <typename Type, uint32_t rows_ = 1, uint32_t cols_ = 1>
class Matrix_Base{
// ...
static constexpr uint32_t rows = rows_;
static constexpr uint32_t cols = cols_;
bool is_runtime_sized;
// ...
};
template <typename T, uint32_t R, uint32_t C>
bool Matrix_Base<T,R,C>::is_runtime_sized = internal::Runtime_Size_Helper<R,C>::value();
这使得该mpl函数的结果成为Matrix_Base类的成员。到目前为止一切都很好。
我想使用某种形式的间接通过传递实例化的对象来确定runtime_size_type的值。根据示例代码,确定这一点的唯一必需信息是col和row的uint32_t参数。
对于实例化的Matrix_Base对象,相关信息永远不会从其编译类型值更改。矩阵的大小是不可变的;大小将通过模板参数设置,或者 - 对于运行时大小的矩阵 - 通过构造函数设置。在这两种情况下,模板参数都是固定的,并且是类型信息的一部分。我将这些信息保存为类中的静态变量,我甚至尝试添加一个包含所有模板参数的typedef作为my_type typename typename Matrix_Base<T,rows_, cols_, ...> my_type
,但我似乎无法弄清楚如何编写一个我可以使用的元函数传递一个Matrix_Base对象(显然作为参考或指针)并重新提取相关信息。
我完全愿意合并(其他)boost库,如果它们能提供必要的功能的话。
希望这一点很清楚。请告诉我这里有什么东西不清楚,或者说这只是愚蠢的。
祝你好运, 什穆埃尔
编辑了文本,以便更清楚地解决问题
答案 0 :(得分:1)
执行您似乎想要的最快捷方式(您没有详细指定它)是让您的矩阵类模板继承存储类模板,并根据您是否专门化存储类MPL谓词返回true或false
#include <array>
#include <iostream>
#include <vector>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/comparison.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/logical.hpp>
using namespace boost;
// in C++98, use
// template<int R, int C>
// struct is_runtime_sized: mpl::if<
// ...
// >::type {};
template<int R, int C>
using is_runtime_sized = typename mpl::if_<
mpl::or_<
mpl::equal_to<mpl::int_<R>, mpl::int_<0>>,
mpl::equal_to<mpl::int_<C>, mpl::int_<0>>
>,
mpl::true_, mpl::false_
>::type;
请注意,我已经解决了一些不必要的typename
问题,以使MPL谓词更具可读性。
template<class T, int R, int C, bool = is_runtime_sized<R, C>::value>
struct MatrixStorage
{
MatrixStorage() = default;
MatrixStorage(int r, int c): data_(r * c) {} // zero-initializes
protected:
std::vector<T> data_;
};
template<class T, int R, int C>
struct MatrixStorage<T, R, C, false>
{
MatrixStorage() = default;
MatrixStorage(int, int): data_{} {} // zero-initializes
protected:
std::array<T, R * C> data_;
};
在这里,我分割了动态和静态存储矩阵的实现。前者使用std::vector
,后者使用std:array
。与Eigen类似,两者都有一个默认构造函数,并且都有一个构造函数,它采用零初始化的矩阵维度。
template<class T, int R = 0, int C = 0>
struct Matrix: public MatrixStorage<T, R, C>
{
Matrix() = default;
// In C++98, write:
// Matrix(int r, int c): MatrixStorage<T, R, C>(r, c) {}
using MatrixStorage<T, R, C>::MatrixStorage;
int size() const { return this->data_.size(); }
};
实际的Matrix
类继承自MatrixStorage
,并根据当前存储的数据返回size()
。
int main()
{
Matrix<int> m_dyn(3, 3);
std::cout << m_dyn.size() << "\n"; // 9
Matrix<int, 2, 2> m_stat;
std::cout << m_stat.size() << "\n"; // 4
}
Live Example。如您所见,动态分配的矩阵大小为9,静态大小的矩阵大小为4.请注意,上面的代码中有两个小的C ++ 11特性,如果需要,可以轻松解决这些问题。使用C ++ 11。