c++ - 如何(优雅地)将任意数量的输入输出参数旋转到函数?

标签 c++ pointers reference rotation variadic-templates

Input: 1, 2, 3, 4Output: 2, 3, 4, 1 我的解决方案: play with my code

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;
}
我想旋转任意数量的元素,如上所述。我的解决方案似乎有效,但在我看来,它不是很“优雅”。我不喜欢我必须在这里初始化一个 vector 。有没有办法在没有 vector 的情况下完成同样的事情?也许用递归?
理想情况下,我还想传递引用而不是指针。

最佳答案

这是一个不使用 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};
}
这是一个 demo .

编辑:上述解决方案很优雅,但不正确,因为似乎分配给 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 个移动赋值。据我所知,第一个解决方案不可能做到这一点。显然,这是正确的,这也是一个很大的优势:)
这是一个 demo这也显示了所做的拷贝/移动。

这是@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);
}
这是一个 demo .

关于c++ - 如何(优雅地)将任意数量的输入输出参数旋转到函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63529881/

相关文章:

java - 将 std::max 转换为 Java

c++ - 那么我在哪里可以找到最好的在线 C++ 标准库引用资料?

c++ - 命名空间内未引用的函数

c - 如果指针只是地址,为什么我不能将特定的 int 地址分配给指针?

c - 由于不使用三重指针而出现段错误

ios - 体系结构的 undefined symbol x86_64 : "_OBJC_CLASS_$_UIPointerShape", "_OBJC_CLASS_$_UIPointerStyle"

c++ - 关于C++虚拟继承的问题

C++ 转换为派生结构和父结构

c++ - 原始指针和智能指针混合函数重载

c++ - 添加 <iostream> 会破坏 g++-7 中的代码