【问题标题】:How to declare a tuple with uniform type without <array>?如何在没有 <array> 的情况下声明具有统一类型的元组?
【发布时间】:2017-04-24 07:38:55
【问题描述】:

我想要一个我正在编写的函数为某个值 N 返回一个 N foos 的元组(N 不是代码的一部分)。

如果是 C++14,我可能会绕过实际声明任何内容,只需使用 auto 作为返回类型,但这在 C++11 中不起作用。我不想使用-&gt; auto decltype,因为那会意味着很多文本,我不妨写,比如std::tuple{foo, foo, foo, foo}

另一种选择是让返回类型为std::array&lt;foo, N&gt;;这应该可以工作。不过,我想知道的是,我是否可以在不拉入所有 &lt;array&gt; 的情况下度过难关,我实际上并不需要它的功能。

【问题讨论】:

  • 当你想要一个不同类型的有序集合时,通常会选择元组。一个数组 是 N 个 foo,使用起来更简单

标签: c++ c++11 tuples idioms stdarray


【解决方案1】:
#include <tuple>
#include <utility>
#include <iostream>

namespace detail {

// the concept of N Ts. This is a type generator.
template<class T, std::size_t N>
struct tuple_of_n
{
  using rest_tuple = typename tuple_of_n<T, N-1>::type;
  using type = decltype(std::tuple_cat(std::declval<std::tuple<T>>(), std::declval<rest_tuple>()));
};

// terminal case where N is 0    
template<class T>
struct tuple_of_n<T, 0>
{
  using type = std::tuple<>;
};
}

// typedef turns the generator into a type
template<class T, std::size_t N>
  using tuple_of_n = typename detail::tuple_of_n<T, N>::type;

int main() {

  // test
  using two_ints = tuple_of_n<int, 2>;

  // proof of equivalency
  two_ints is = std::make_tuple(2, 4);

  std::cout << std::get<0>(is) << std::endl;
  std::cout << std::get<1>(is) << std::endl;

  return 0;
}

【讨论】:

  • 终端情况不应该是0而不是1吗?
  • @jaggedSpire 我认为这是合理的。这是一个简单的编辑。
【解决方案2】:

使用 integer_sequence [integer_seq.h] 的外部实现的 c++11 方法对 c++14 进行了一些样式化,如下所示:

#include <tuple>
#include <utility>
#include <iostream>
#include <initializer_list>
#include "integer_seq.h"

using namespace redi;


template <class T, std::size_t N, class = make_index_sequence<N>>
struct tuple_generator;

template <std::size_t, class T>
using typer = T;

template <class T, std::size_t N, std::size_t... Is>
struct tuple_generator<T, N, index_sequence<Is...>> {
    using type = std::tuple<typer<Is, T>...>;
};

int main() {
    static_assert(std::is_same<tuple_generator<int, 3>::type, std::tuple<int, int, int>>::value, "!");
}

[live demo]

【讨论】:

  • 您可能应该只包含一个可用的 C++11 的公共实现索引序列,这似乎是可用的,例如在 GitHub 上。
  • 你是对的 - 这可能会使代码更清晰
【解决方案3】:

我将从@Smeeheey 对我提出的另一个问题的回答中回收这个想法:C++ parameter pack, constrained to have instances of a single type?

联系是,你的问题和tuple没有太大关系,真的,

如何制作包含相同类型重复多次的参数包?

最直接的答案是,使用std::make_index_sequence 和一个包扩展:

#include <tuple>
#include <utility>

template <typename T, unsigned n>
struct repeat_tuple {
  template <unsigned>
  struct blah {
    using type = T;
  };

  template <typename IS>
  struct helper;

  template <unsigned ... Is>
  struct helper<std::integer_sequence<unsigned, Is...>> {
    using type = std::tuple<typename blah<Is>::type...>;
  };

  using type = typename helper<std::make_integer_sequence<unsigned, n>>::type;
};

template <typename T, unsigned n>
using repeat_tuple_t = typename repeat_tuple<T, n>::type;

static_assert(std::is_same<repeat_tuple_t<int, 3>, std::tuple<int, int, int>>::value, "");

int main() {}

这最终与 W.F. 的答案相同,但可能更简洁一些。编辑:我猜他的答案是在向后移植 C++14 特征。

tuple_cat 方法不同,这种方法也适用于元组以外的事物。

其实我猜std::tuple 可能是这里的模板模板参数...

:邪恶的眼睛:

【讨论】:

    【解决方案4】:

    这在常规函数中是不可能的。

    函数的返回类型是固定的,不能改变。具有不同类型的元组每个都是不同的类型,因此您不能有一个返回不同元组类型的函数。

    示例:tuple&lt;int, int&gt;tuple&lt;int,int,int&gt; 相比是不同的类型

    话虽如此,您可以使用函数模板(make_shared 以这种方式实现)来执行此操作,调用者在进行函数调用时显式指定预期的返回元组类型。我认为这不是很好的可用性,因为元组很冗长。

    使用 std::array(或 std::vector)可能是更简单的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-24
      • 1970-01-01
      • 1970-01-01
      • 2017-10-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多