我目前正在为高级综合创建算术运算库。
为此,我还创建了一个库来操作位和位向量,就像在VHDL中完成一样。为了使我的库可以合成,几乎所有东西都必须在编译时解决。
但是,我遇到了循环问题。
的确,我希望能够写出类似的东西:
const int N = 5;
for(int i = 0; i < N-2; i++) {
x.bit<i+2>() = x.bit<i>();
}
当然,它不会编译,因为i
是一个变量而不是在编译时确定的常量。
但是,N
是常量,此代码严格等同于:
x.bit<2>() = x.bit<0>();
x.bit<3>() = x.bit<1>();
x.bit<4>() = x.bit<2>();
编译并完美地运作。
有没有办法让编译器(在我的情况下为gcc)展开循环,因为N
是常量?或者定义一个宏或constexpr
,它可以用干净的语法来做到这一点?这相当于VHDL中生成的。
答案 0 :(得分:3)
虽然constexpr
在C ++ 14/17中功能更强大,但还不可能将这种编译时/模板代码与普通循环混合使用。有一些关于引入可能在未来版本的C ++中启用它的构造的讨论。现在你有几个选择,要么递归调用带有整数模板参数的函数,要么可能更简单,在这种情况下是C ++ 17 fold expression。你也可以使用C ++ 11可变参数模板扩展来获得类似的结果来折叠表达式,尽管折叠表达式更强大。
刚刚看到你关于被C ++ 11困住的评论,你认为使用递归函数方法可能会更好。我已经在示例中添加了这种方法。
如果您能够使用C ++ 14,您可能还需要考虑完全移入constexpr
函数/类型的土地,这样您的bit<I>()
函数就不会被模板化,而只会是{{1} 1}}函数constexpr
。然后,您可以使用普通函数和循环。鉴于对bit(i)
函数的C ++ 11限制,在您的情况下可能不太有用。我已经使用这种方法添加了一个示例。
constexpr
答案 1 :(得分:2)
也没有std::integer_sequence
(但我建议实现替代并使用它),在C ++ 11中你可以使用模板部分特化。
我的意思是你可以实现像
这样的东西template <int I, int Sh, int N>
struct shiftVal
{
template <typename T>
static int func (T & t)
{ return t.template bit<I+Sh>() = t.template bit<I>(),
shiftVal<I+1, Sh, N>::func(t); }
};
template <int I, int Sh>
struct shiftVal<I, Sh, I>
{
template <typename T>
static int func (T &)
{ return 0; }
};
并且您的周期变为
shiftVal<0, 2, N-2>::func(x);
以下是一个完整的工作示例
#include <array>
#include <iostream>
template <std::size_t N>
struct foo
{
std::array<int, N> arr;
template <int I>
int & bit ()
{ return arr[I]; }
};
template <int I, int Sh, int N>
struct shiftVal
{
template <typename T>
static int func (T & t)
{ return t.template bit<I+Sh>() = t.template bit<I>(),
shiftVal<I+1, Sh, N>::func(t); }
};
template <int I, int Sh>
struct shiftVal<I, Sh, I>
{
template <typename T>
static int func (T &)
{ return 0; }
};
int main ()
{
foo<10U> f { { { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 } } };
for ( auto const & i : f.arr )
std::cout << i << ' ';
std::cout << std::endl;
shiftVal<0, 2, 10-2>::func(f);
for ( auto const & i : f.arr )
std::cout << i << ' ';
std::cout << std::endl;
}
答案 2 :(得分:0)
没有其他人根据std::integer_sequence
的C ++ 11模拟生成一个例子(正如WF,Passer By和Sopel以及更简单的解决方案IMHO所建议的那样)所以我提出了以下一个({{1}在现实中{}和std::index_sequence
:模拟std::make_index_sequence
更复杂)
std::integer_sequence
因此,用于重现被询问循环的函数(带有函数助手)可以写成
模板
template <std::size_t ...>
struct indexSequence
{ };
template <std::size_t N, std::size_t ... Next>
struct indexSequenceHelper : public indexSequenceHelper<N-1U, N-1U, Next...>
{ };
template <std::size_t ... Next>
struct indexSequenceHelper<0U, Next ... >
{ using type = indexSequence<Next ... >; };
template <std::size_t N>
using makeIndexSequence = typename indexSequenceHelper<N>::type;
并且跟随广告
void shiftValHelper (T & t, indexSequence<Is...> const &)
{
using unused = int[];
(void)unused { 0,
(t.template bit<Is+Sh>() = t.template bit<Is>(), 0)... };
}
template <std::size_t Sh, std::size_t N, typename T>
void shiftVal (T & t)
{ shiftValHelper<Sh>(t, makeIndexSequence<N>{}); }
以下是一个完整的工作示例
shiftVal<2, N-2>(x);