【发布时间】:2019-01-19 15:08:05
【问题描述】:
我有一些辅助代码使用编译时索引执行向量重新洗牌。最重要的是生成的代码尽可能高效。我依赖于带有折叠表达式的参数包,我想知道编写此类代码的最佳实践是什么。
一个实际的例子:假设有一个函数insert 将容器y 的元素插入容器x 的位置Ii,其中位置是编译时常量。这个函数的基本签名是这样的:
template<size_t... Ii, size_t Xsize, size_t Size>
constexpr container<Xsize> insert(container<Xsize> x, container<Ysize> y);
它的调用方式如下:insert<0, 2>(x, y)。我看到了两种明显的实现可能性。
首先:使用辅助索引变量迭代y:
template<size_t... Ii, size_t Xsize, size_t Size>
constexpr container<Xsize> insert(container<Xsize> x, container<Ysize> y) {
int i = 0;
((x[Ii] = y[i++]), ...);
return x;
}
我对这个解决方案的问题是变量i:我必须依靠编译器来优化它。
第二种解决方案避免了任何运行时依赖,但它需要一个辅助函数,使得整个实现相当难看:
template<size_t... Ii, size_t... Yi, size_t Xsize, size_t Size>
constexpr container<Xsize> insert_(container<Xsize> x, container<Ysize> y, std::index_sequence<Yi...>) {
((x[Ii] = y[Yi]), ...);
return x;
}
template<size_t... Ii, size_t Xsize, size_t Size>
constexpr container<Xsize> insert(container<Xsize> x, container<Ysize> y) {
return insert_<Ii...>(x,y, std::make_index_sequence<sizeof...(Ii)> {});
}
有没有办法避免运行时变量和辅助函数?
【问题讨论】:
-
std::make_index_sequence<>基本上是为这样的东西设计的。即使它需要一个辅助功能,我喜欢你的第二个解决方案。如果没有另一个函数来接收它,你就不能真正使用索引序列。 -
你有什么理由认为编译器不会优化运行时变量吗?诚然,这很尴尬,但如果它完成了工作......?
-
例如在 -O1 有 nothing。
-
@Barry,是的,编译器非常擅长优化它。但有时它仍然不完美。问题是,这是用于 SIMD 处理的,无论如何,这些调用中的大多数都应该编译成一两个 SIMD 指令,我正在努力解决一些可能会阻止优化器发挥最佳工作的问题。
标签: c++ c++17 variadic-templates template-meta-programming fold-expression