我尝试从块矩阵中提取所有单个块。但是,我使用的库中的 BlockMatrixClass 只允许通过以下索引访问:
Dune::index_constant<0>(), Dune::index_constant<1>(),...
它们解析为 std::integral_constant
如何将以下代码更改为有效?无需更改库。
for(std::size_t i=0; i<3; i++){
for(std::size_t j=0; j<3; j++){
const auto& m = jacobian[Dune::index_constant<i>()][Dune::index_constant<j>()];
}
}
目前我收到错误
error: the value of ‘j’ is not usable in a constant expression
401 | t auto& m = jacobian[Dune::index_constant<i>()][Dune::index_constant<j>()];
答案 0 :(得分:3)
迭代编译时间序列并不是一个完全解决的问题,因为它们都依赖于各种解决方法,并且有很多方法可以做到。
我的首选方法是使用索引序列,并使用折叠表达式展开它:
简单定义:
template<typename T, T... S, typename F>
constexpr void for_sequence(std::integer_sequence<T, S...>, F&& f) {
(static_cast<void>(f(std::integral_constant<T, S>{})), ...);
}
然后,像这样使用它:
for_sequence(std::make_index_sequence<3>{}, [&](auto i) {
for_sequence(std::make_index_sequence<3>{}, [&](auto j) {
const auto& m = jacobian[Dune::index_constant<i>()][Dune::index_constant<j>()];
});
});
这里的变量 i
和 j
是整型常量,可以用在模板参数中。您发送给函数的实际 std::integer_sequence
决定了实例化最内层 lambda 的值。
如果jacobian
可以直接使用那些积分常数而不是它们自己的Dune::index_constant
,你可以简单地写成:
for_sequence(std::make_index_sequence<3>{}, [&](auto i) {
for_sequence(std::make_index_sequence<3>{}, [&](auto j) {
const auto& m = jacobian[i][j];
});
});
答案 1 :(得分:1)
#include <cstdint>
#include <cstddef>
#include <utility>
template <size_t index, size_t end>
void for_loop () {
if constexpr (index == end) {
return;
}
constexpr size_t i = index / 3;
constexpr size_t j = index % 3;
const auto& m = jacobian[Dune::index_constant<i>()][Dune::index_constant<j>()];
impl<index + 1, end>();
}
template <size_t end>
void for_loop_to() {
for_loop<0, end>();
}
int main ()
{
for_loop_to<9>();
}
这样的东西对 constexpr for 循环类型的东西有用吗?这适用于 C++17(因为它需要 constexpr if
),但更详细的版本将在早期的 C++ 版本中实现。此外,我没有将 jacobian
连接到内部函数,但您可以使用结构包装器来实现。
答案 2 :(得分:1)
您可以展开循环:
const auto& m = jacobian[Dune::index_constant<0>()][Dune::index_constant<0>()];
const auto& m = jacobian[Dune::index_constant<0>()][Dune::index_constant<1>()];
const auto& m = jacobian[Dune::index_constant<0>()][Dune::index_constant<2>()];
const auto& m = jacobian[Dune::index_constant<1>()][Dune::index_constant<0>()];
const auto& m = jacobian[Dune::index_constant<1>()][Dune::index_constant<1>()];
const auto& m = jacobian[Dune::index_constant<1>()][Dune::index_constant<2>()];
const auto& m = jacobian[Dune::index_constant<2>()][Dune::index_constant<0>()];
const auto& m = jacobian[Dune::index_constant<2>()][Dune::index_constant<1>()];
const auto& m = jacobian[Dune::index_constant<2>()][Dune::index_constant<2>()];
如果那不是一个选项,您可以应用某种形式的编译时间:
#include <utility>
#include <iostream>
template <template<size_t> class F,size_t ... I>
void for_impl(std::index_sequence<I...>){
(F<I>{}(),...);
}
template <template<size_t> class F,std::size_t N,typename Indices = std::make_index_sequence<N>>
void for_(){
for_impl<F>(Indices{});
}
template <size_t i>
struct foo{
void operator()() {
std::cout << i << "\n";
}
};
int main() {
for_<foo,5>();
}
这里只概述了一个循环。我不确定您是否需要在编译时展开两个循环。在示例中,foo
是将循环体包裹在其中的模板。