Hen*_*nke 12 c++ templates template-meta-programming variadic-templates c++11
我写了一个类multi_array,它是std::array多维度的扩展.
template <typename T, std::size_t... N>
class multi_array {
template <std::size_t... I, typename... Idx>
constexpr std::size_t linearized_index(meta::index_sequence<I...>,
Idx... idx) const {
std::size_t index = 0;
using unpack = std::size_t[];
(void)unpack{0UL,
((void)(index = (index + unpack{std::size_t(idx)...}[I]) *
meta::pack_element<I + 1, N...>::value),
0UL)...};
return index + unpack{std::size_t(idx)...}[sizeof...(idx) - 1];
}
// Storage
T m_data[meta::product<N...>::value];
//...
};
Run Code Online (Sandbox Code Playgroud)
我设法获得constexpr元素访问权限,但仅限于C++ 14.问题是功能linearized_index.它在编译时计算线性化索引.为了做到这一点,它以某种方式减少了索引的元组和维度的元组.对于这种减少,我需要在函数内部使用局部变量,但在C++ 11中不允许这样做.我的环境不允许使用C++ 14.我可以以某种方式重写此函数以使用C++ 11吗?
我已经准备了一个完整的(不是那么简单的)用C++编写的例子14.
#include <cstddef> // std::size_t
namespace meta {
// product
template <std::size_t...>
struct product;
template <std::size_t head, std::size_t... dim>
struct product<head, dim...> {
static constexpr std::size_t const value = head * product<dim...>::value;
};
template <>
struct product<> {
static constexpr std::size_t const value = 1;
};
// pack_element
template <std::size_t index, std::size_t head, std::size_t... pack>
struct pack_element {
static_assert(index < sizeof...(pack) + 1, "index out of bounds");
static constexpr std::size_t const value =
pack_element<index - 1, pack...>::value;
};
template <std::size_t head, std::size_t... pack>
struct pack_element<0, head, pack...> {
static constexpr std::size_t const value = head;
};
// index_sequence
// https://stackoverflow.com/a/24481400
template <std::size_t... I>
struct index_sequence {};
template <std::size_t N, std::size_t... I>
struct make_index_sequence : public make_index_sequence<N - 1, N - 1, I...> {};
template <std::size_t... I>
struct make_index_sequence<0, I...> : public index_sequence<I...> {};
} // namespace meta
template <typename T, std::size_t... N>
class multi_array {
template <std::size_t... I, typename... Idx>
constexpr std::size_t linearized_index(meta::index_sequence<I...>,
Idx... idx) const {
std::size_t index = 0;
using unpack = std::size_t[];
(void)unpack{0UL,
((void)(index = (index + unpack{std::size_t(idx)...}[I]) *
meta::pack_element<I + 1, N...>::value),
0UL)...};
return index + unpack{std::size_t(idx)...}[sizeof...(idx) - 1];
}
// Storage
T m_data[meta::product<N...>::value];
public:
constexpr multi_array() {}
template <typename... U>
constexpr multi_array(U... data) : m_data{T(data)...} {}
template <typename... Idx>
constexpr T operator()(Idx... idx) const noexcept {
std::size_t index = linearized_index(
meta::make_index_sequence<sizeof...(idx) - 1>{}, idx...);
return m_data[index];
}
};
int main() {
constexpr multi_array<double, 2, 2> const b = {0, 0, 0, 1};
static_assert(b(1, 1) == 1, "!");
}
Run Code Online (Sandbox Code Playgroud)
您使用的关键部分index是迭代循环:
index = (index*a) + b
Run Code Online (Sandbox Code Playgroud)
在您自己的C++ 14解决方案中,使用了解包参数包的技巧.在C++ 11中,您可以在递归constexpr函数中表达它:
struct mypair {
size_t a;
size_t b;
};
constexpr std::size_t foo(std::size_t init) {
return init;
}
template<class... Pair>
constexpr std::size_t foo(std::size_t init, mypair p0, Pair... ps) {
return foo((init+p0.a)*p0.b, ps...);
}
Run Code Online (Sandbox Code Playgroud)
我们使用mypair而不是std::pair因为std::pairC++ 11中的构造函数不是constexpr.然后你的迭代循环可以直译为:
template <std::size_t... I, typename... Idx>
constexpr std::size_t linearized_index(meta::index_sequence<I...>,
Idx... idx) const {
using unpack = std::size_t[];
return foo(0, mypair{unpack{std::size_t(idx)...}[I], meta::pack_element<I+1, N...>::value}...) + unpack{std::size_t(idx)...}[sizeof...(idx) - 1];
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
359 次 |
| 最近记录: |