与可变基类交换

时间:2017-01-19 21:09:45

标签: c++ c++11 c++14

我正在尝试编写一个元组,而我还没想到的一件事是如何编写一个交换。 (简化)类型如下所示:

template<size_t I, typename T>
struct tuple_elem {
    ...

    void swap(tuple_elem& other)
    {
        // implemented
    }
};

template<size_t... Is, typename... Ts>
struct tuple_impl<std::index_sequence<Is...>, Ts...>
    : private tuple_elem<Is, Ts>...
{
    void swap(tuple_impl& other)
    {
        // ???
    }
};

我一直在尝试在// ???标记的地方解压缩索引和类型,但在我的生活中不能弄清楚如何。我尝试过这样的事情:

static_cast<tuple_elem<Is, Ts>&>(*this)->swap(
            static_cast<tuple_elem<Is, Ts>&>(other))...;

但是给出了错误:

Tuple.hpp:182:64: error: expected ';' before '...' token
                 static_cast<tuple_elem<Is, Ts>&>(other))...;
                                                         ^~~
Tuple.hpp:182:67: error: parameter packs not expanded with '...':
                 static_cast<tuple_elem<Is, Ts>&>(other))...;
                                                            ^

帮助!

1 个答案:

答案 0 :(得分:0)

好的,首先。通过以您尝试的方式扩展包,您将无法获得有效的表达。试着写出来。

现在我将从最简单的开始。 (我假设你正在实现一个元组,所以你有一些标准的实用程序std::tuple。)如果你的编译器实现了C ++ 17的fold表达式,那么交换就可以这么简单:

template<typename... Tn, typename... Tn2, size_t... Is>
void swap_impl(tuple<Tn...>& a, tuple<Tn2...>& b, std::index_sequence<Is...>)
{
    using std::swap;
    (swap(get<Is>(a), get<Is>(b)), ...);
}

使用两个元组和std::index_sequence_for<Is...>{}调用。 get<I>(tuple)易于实施,这是您static_cast<tuple_elem<Is, Ts>&>(tuple)的事情。

另一方面,如果您只能访问C ++ 14,我的方法将如下所示:

template<size_t N>
struct tuple_ops
{
    template<typename T, typename T2, size_t I = tuple_size<T>::value - N>
    static constexpr void swap(T& a, T2& b) 
    {
        using std::swap;
        swap(get<I>(a), get<I>(b));
        return tuple_ops<N - 1>::swap(a, b);
    }
};

显然,与任何递归方法一样,您需要为0提供基本情况。

template<>
struct tuple_ops<0>
{
    template<typename T, typename T2>
    static constexpr void swap(T&, T2&) noexcept {}
};

然后您的交换功能如下:

constexpr void swap(tuple& rhs) {
     tuple_ops<sizeof...(Tn)>::swap(*this, rhs);
}

注意:代码未经测试。