【问题标题】:Iterating on a tuple... again迭代一个元组......再次
【发布时间】:2015-02-15 21:32:09
【问题描述】:

我做C++有一段时间了,但我对模板不熟悉。

最近,我尝试编写一个包装std::vector<std::tuple<Types...>> 的类。这个类必须有成员函数,我真的需要能够迭代 元组。事实上,如果我能够打印元组的每个元素(按顺序),我就能做我需要的一切。

我找到了一个使用演员表的解决方案,但我对它不是很有信心,因为它是基于我不太喜欢的演员表(另外,当我尝试使用 static_cast 时,它不会再编译)。

我的问题是,以下代码是否正确、可移植、是否是 hack,我是否应该找到另一种方法来做到这一点而不是使用这个演员?此外,这个演员可能是一个运行时演员,对吧?没有这个有没有办法做我想做的事?

std::ostream& operator<<(std::ostream& out, std::tuple<> const& tuple)
{
    return out; // Nothing to do here
}

template<typename First, typename... Types>
std::ostream& operator<<(std::ostream& out, std::tuple<First, Types...> const& tuple)
{
    out << std::get<0>(tuple) << " ";

    // The cast that I don't like
    return out << (std::tuple<Types...>&) tuple;
}

int main()
{
    auto tuple = std::make_tuple(1, 2.3, "Hello");
    std::cout << tuple << std::endl;
    return 0;
}

提前感谢您的回答。

【问题讨论】:

  • 该演员表看起来像reinterpret_cast。所以不,不好。
  • 在使用 clang++ 和 libc++ 时甚至 produces a segfault
  • @dyp 这正是我想知道的,谢谢!
  • 我建议也看看 Boost.Fusion(尤其是for_each)。它可能会也可能不会过大,但它肯定更容易编写。

标签: c++ templates variadic-templates c++14


【解决方案1】:

使用std::index_sequence_for 获得乐趣和利润。

template <typename TupleLike, size_t ... Inds>
std::ostream& PrintHelper(std::ostream& out, TupleLike const& tuple, std::index_sequence<Inds...>)
{
  int unused[] = {0, (void(out << std::get<Inds>(tuple) << " "), 0)...};
  (void)unused;
  return out;
}

template<typename... Types>
std::ostream& operator<<(std::ostream& out, std::tuple<Types...> const& tuple)
{
  return PrintHelper(out, tuple, std::index_sequence_for<Types...>());
}

编辑:Live Demo。感谢@dyp。这使用了来自this answer 的扩展技巧。

【讨论】:

  • 请注意,这会导致 MSVC 上的堆栈损坏,但使用 std::array&lt;&gt; 的等效项可以正常工作。
  • VC++ 2015 已修复堆栈损坏问题。
【解决方案2】:

我找到了另一种方法来做我想做的事。我使用了this article,它可以按降序打印元组的元素,我使用第二个索引J == std::tuple_size&lt;std::tuple&lt;Types...&gt;&gt;::value - I,所以我可以在I==0时专门化模板。

template<std::size_t I, std::size_t J, typename... Types>
struct printHelper
{
    std::ostream& operator()(std::ostream& out, std::tuple<Types...> const& tuple)
    {
        out << std::get<J>(tuple) << " ";

        // Recursive call without cast
        return printHelper<I-1,J+1,Types...>{}(out, tuple);
    };
};

// Specialization on the last element when I==0
template<std::size_t J, typename... Types>
struct printHelper<0,J,Types...>
{
    std::ostream& operator()(std::ostream& out, std::tuple<Types...> const& tuple)
    {
        // Nothing to do here
        return out;
    }
};

template<typename... Types>
std::ostream& operator<<(std::ostream& out, std::tuple<Types...> const& tuple)
{
    return printHelper<std::tuple_size<std::tuple<Types...>>::value, 0, Types...>{}(out, tuple);
}

【讨论】:

    猜你喜欢
    • 2011-10-28
    • 2011-07-14
    • 2011-08-15
    • 1970-01-01
    • 1970-01-01
    • 2012-08-10
    • 2021-12-01
    • 2013-07-01
    • 2021-10-05
    相关资源
    最近更新 更多