用于获取多个容器引用的可变参数模板
Variadic template for taking multiple containers references
我想要一个函数获取对容器的多个引用并返回所有容器的元素组合。由于这个操作是在一个非常热的循环中执行的,我希望能够静态地展开尽可能多的操作,而无需编写基本相同函数的 5 个实例。
我正在执行的算法基本上表现为
const auto result = s0 + a1 * s1 + a2 * s2 + ...
其中所有 si
都是包含相同数量元素的容器。要求和的元素数量在编译时已知。
我正在寻找的函数应该表现为:(假设)
inline Container sum(const Container& s0, double a1, const Container& s2, ....){
auto result = Container(s0);
for (int i = 0; i < result.size(); ++i)
result[i] += a1 * s1[i] + a2 * s2[i] + ...;
return result;
}
出于性能原因,不希望编写一些带有运行时边界检查的内部循环。此外,在尝试使用运行时边界时,我遇到了无法轻易将可变数量的引用传递给函数的问题,在这种情况下我应该只求助于指针吗?
所有代码都必须是有效的 C++11,我无法在此项目中使用更现代的编译器。
我将 double
和 container
分组以将代码简化为:
template <typename C, typename ... Cs>
C sum(const C& c0, const Cs&... cs)
{
auto result = c0;
for (int i = 0; i < result.size(); ++i)
#if 0 // C++17
result[i] += (cs[i] + ...);
#else // C++11/C++14
const int dummy[] = {0, (static_cast<void>(result[i] += cs[i]), 0)...};
static_cast<void>(dummy); // avoid warning for unused variable.
#endif
return result;
}
因此,对于分组,类似于:
template <typename C>
struct MulContainer
{
auto operator [](int i) const { return d * c[i]; }
double d;
const C& c;
};
所以打电话,而不是
sum(c0, a1, c1, a2, c2);
你会:
sum(c0, MulContainer{a1, c1}, MulContainer{a2, c2});
如果确实需要,使用 std::index_sequence
您可能仍然有首次调用语法。
template <typename C, std::size_t... Is, typename Tuple>
C sum_impl(const C& c0, std::index_sequence<Is...>, const Tuple& t)
{
return sum(c0, MulContainer{std::get<2 * Is>(t), std::get<2 * Is + 1>(t)}...);
}
template <typename C, typename ... Ts>
C final_sum(const C& c0, const Ts&... ts)
{
static_assert(sizeof...(Ts) % 2 == 0);
return sum_impl(c0, std::make_index_sequence<sizeof...(Ts) / 2>{}, std::tie(ts...));
}
std::index_sequence
是 C++14,但可以在 C++11 中实现。
我想要一个函数获取对容器的多个引用并返回所有容器的元素组合。由于这个操作是在一个非常热的循环中执行的,我希望能够静态地展开尽可能多的操作,而无需编写基本相同函数的 5 个实例。
我正在执行的算法基本上表现为
const auto result = s0 + a1 * s1 + a2 * s2 + ...
其中所有 si
都是包含相同数量元素的容器。要求和的元素数量在编译时已知。
我正在寻找的函数应该表现为:(假设)
inline Container sum(const Container& s0, double a1, const Container& s2, ....){
auto result = Container(s0);
for (int i = 0; i < result.size(); ++i)
result[i] += a1 * s1[i] + a2 * s2[i] + ...;
return result;
}
出于性能原因,不希望编写一些带有运行时边界检查的内部循环。此外,在尝试使用运行时边界时,我遇到了无法轻易将可变数量的引用传递给函数的问题,在这种情况下我应该只求助于指针吗?
所有代码都必须是有效的 C++11,我无法在此项目中使用更现代的编译器。
我将 double
和 container
分组以将代码简化为:
template <typename C, typename ... Cs>
C sum(const C& c0, const Cs&... cs)
{
auto result = c0;
for (int i = 0; i < result.size(); ++i)
#if 0 // C++17
result[i] += (cs[i] + ...);
#else // C++11/C++14
const int dummy[] = {0, (static_cast<void>(result[i] += cs[i]), 0)...};
static_cast<void>(dummy); // avoid warning for unused variable.
#endif
return result;
}
因此,对于分组,类似于:
template <typename C>
struct MulContainer
{
auto operator [](int i) const { return d * c[i]; }
double d;
const C& c;
};
所以打电话,而不是
sum(c0, a1, c1, a2, c2);
你会:
sum(c0, MulContainer{a1, c1}, MulContainer{a2, c2});
如果确实需要,使用 std::index_sequence
您可能仍然有首次调用语法。
template <typename C, std::size_t... Is, typename Tuple>
C sum_impl(const C& c0, std::index_sequence<Is...>, const Tuple& t)
{
return sum(c0, MulContainer{std::get<2 * Is>(t), std::get<2 * Is + 1>(t)}...);
}
template <typename C, typename ... Ts>
C final_sum(const C& c0, const Ts&... ts)
{
static_assert(sizeof...(Ts) % 2 == 0);
return sum_impl(c0, std::make_index_sequence<sizeof...(Ts) / 2>{}, std::tie(ts...));
}
std::index_sequence
是 C++14,但可以在 C++11 中实现。