Input: 1, 2, 3, 4
Output: 2, 3, 4, 1
我的解决方案: 玩我的代码
template <typename T, typename ... Param>
void rotate(T* first, Param* ... params) {
std::vector<T*> tmp = {first, params...};
if (tmp.size() <= 1) {return;}
T f = *first;
for (size_t i = 1; i < tmp.size(); ++i) {
*tmp.at(i - 1) = *tmp.at(i);
}
*tmp.at(tmp.size() - 1) = f;
}
我想如上所述旋转任意数量的元素。我的解决方案似乎有效,但是在我看来,这不是很“优雅”。我不喜欢在这里初始化向量。没有向量,有没有办法完成同一件事?也许有递归?
理想情况下,我还要传递引用而不是指针。
这是一个不使用的INCORRECT解决方案std::vector
,其中所有参数均通过引用传递,并且仅需要复制一个元素:
// THIS IS WRONG, SEE EDIT BELOW
template<typename T, typename ...Ts>
void rotate(T& first, Ts& ...rest)
{
auto first_copy = first;
std::tie(first, rest...) = {rest..., first_copy};
}
这是一个演示。
编辑:上面的解决方案是优雅,但不正确,因为似乎std::tuple
未指定分配给成员的顺序。上面的代码依赖于std::tie
要从左到右完成的参数分配,因此该解决方案不起作用。
这是使用的更详细的解决方案std::apply
,可以保证按顺序调用传入的元组的参数:
template<typename T, typename ...Ts>
void rotate(T& first, Ts& ...rest)
{
auto first_copy = first;
std::apply([&](auto&... lhs) {
std::apply([&](auto&... rhs) {
((lhs = std::move(rhs)), ...);
}, std::tuple<T&, Ts&...>{rest..., first_copy});
}, std::tuple<T&, Ts&...>{first, rest...});
}
尽管这比较冗长,但与第一个解决方案不同,它第一个执行1个复制构造和N个复制分配,但该解决方案的优点是仅执行1个复制构造和N个移动分配。据我所知,第一种解决方案是不可能的。显然,这是正确的,这也是一个很大的优势:)
这是一个演示,还显示了所做的复制/移动。
这是@ max66提供的甚至更简单的解决方案,它与以下解决方案一样有效std::apply
:
template<typename T, typename ...Ts>
void rotate(T& first, Ts& ...rest)
{
T first_copy{first};
[&](auto& first_ref, auto & ... rest_ref) {
first = std::move(first_ref);
(..., (rest = std::move(rest_ref)));
} (rest..., first_copy);
}
这是一个演示。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句