【问题标题】:Variadic templates. Some issues可变参数模板。一些问题
【发布时间】:2016-04-28 02:09:17
【问题描述】:
template <class... T_values>
class Thing {
public:
  void something(T_values... values) {
    tuple_ = std::tuple<T_values...>(values...);
  }

  void do_something_with_values() {
     call_yadda_with_tuple(tuple_,
      std::index_sequence_for<T_value...>())
  }

  void yadda(T... values);

private:
  //The helper method.
  template<std::size_t... Is>
  void call_yadda_with_tuple(const std::tuple<T_values...>& tuple,
    std::index_sequence<Is...>) {
    yadda(std::get<Is>(tuple)...);
  }

  std::tuple<T_values...> tuple_;
};

以上源码来自:https://www.murrayc.com/permalink/2015/12/05/modern-c-variadic-template-parameters-and-tuples/

我想问一些问题:

  1. 什么返回 std::index_sequence_for&lt;T_value...&gt;())
  2. 为什么在yadda(std::get&lt;Is&gt;(tuple)...); 中有Is 而不是Is...?因此,Is 是什么意思? Is... 在未打包(扩展)类型包中,但 Is 是什么。
  3. 特别是,std::get 适合 (1)-(8) (http://en.cppreference.com/w/cpp/utility/tuple/get)
  4. 为什么call_yadda_with_tuple 得到std::index_sequence&lt;Is...&gt;。 毕竟,这种说法是无名的,所以没有用。我想它与扣除类型有关,但我看不出它有什么帮助?

【问题讨论】:

  • #2 std::get&lt;Is&gt;(tuple)...Is... 的每个值解包整个表达式
  • #3 的格式为 1-4(即 get&lt;0&gt;(tuple) 将返回元组中的第一个条目,get&lt;1&gt;(tuple) 将返回第二个,依此类推...)模板参数是一个数字给出要返回的元组条目的索引 - 注意:这是编译时间..
  • #4 函数本身的参数是多余的,推导的类型(提供索引序列是这里相关的,在这种情况下是数字序列0,1,2,3等)
  • std::index_sequencesize_t 的特化 std::integer_sequence。在这里阅读integer_sequence 的提案可能会对您有所帮助open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3658.html

标签: c++ c++11


【解决方案1】:

什么返回 std::index_sequence_for()) ?

假设 T_value... 是 T、T、T(即 3 种类型...)

std::index_sequence<0, 1, 2>

为什么在 yadda(std::get(tuple)...);有 Is 而不是 Is...?因此,是什么意思?是...在未打包(扩展)类型中打包,但它是什么。

Is 表示“Is 的当前值”,而 Is... 正在解包。尾随 ... 导致使用 Is 的表达式解包。

尤其是 std::get 适合 (1)-(8) (http://en.cppreference.com/w/cpp/utility/tuple/get)

在这种情况下,元组引用是const std::tuple&lt;T_values...&gt;&amp;,所以它将是数字 3。

为什么 call_yadda_with_tuple 得到 std::index_sequence。毕竟,这种说法是无名的,所以没有用。我想它与扣除类型有关,但我看不出它有什么帮助?

它只是为了使Is... 存在,因此允许您扩展序列中的所有Is

编辑:

这是一个 cmets 示例,希望能解释发生了什么

#include <utility>
#include <tuple>
#include <string>
#include <iostream>

// for any value I, write a comma and space to stdout
// (i.e. ignore the value I)
template<std::size_t I>
void emit_sep()
{
    std::cout << ", ";
}

// specialise for when I is zero... no comma in this case
template<>
void emit_sep<0>()
{
}

// emit and value at some position I. Use emit_sep<I> to determine whether
// to print a separator
template<std::size_t I, class T>
void emit(const T& t)
{
    emit_sep<I>();
    std::cout << t;
}

// given a tuple type and a sequence of integers (Is...) emit the value
// at each index position of the tuple. Take care to emit a separator only
// before each element after the first one
template<class Tuple, size_t...Is>
void impl_show_it(const Tuple& tup, std::index_sequence<Is...>)
{
    using expand = int[];

    std::cout << "here are the indexes in the index_sequence: ";
    // the following line will expand (in our example) to:
    // void(int[] { 0, 
    //      (emit<0>(0), 0),
    //      (emit<1>(1), 0),
    //      (emit<2>(2), 0),
    //      });
    // and the optimiser will remove the operations which have no observable
    // side-effects (namely, building an array of ints which is never used)
    // so the code emitted will be equivalent to:
    // emit<0>(0); emit<1>(1); emit<2>(2);
    //
    void(expand {
        0,
        (emit<Is>(Is), 0)...
    });
    std::cout << std::endl;

    std::cout << "here are the values in the tuple: ";
    void(expand {
        0,
        (emit<Is>(std::get<Is>(tup)), 0)...
    });
    std::cout << std::endl;
}

// for some tuple type, compute the size of the tuple, build an index sequence
// representing each INDEX in the tuple and then use that sequence to call
// impl_show_it in order to actually perform the write
template<class Tuple>
void show_it(const Tuple& tup)
{
    constexpr auto tuple_size = std::tuple_size<Tuple>::value;
    auto sequence = std::make_index_sequence<tuple_size>();
    impl_show_it(tup, sequence);
}

// make a tuple and then show it on stdout
int main()
{
    auto t = std::make_tuple(6, std::string("hello"), 5.5);
    show_it(t);
}

预期结果:

here are the indexes in the index_sequence: 0, 1, 2
here are the values in the tuple: 6, hello, 5.5

【讨论】:

  • #3 他要求你点击链接并告诉他列出的 std::get 的 8 个变体中哪个是被调用的
  • Is 表示“Is 的当前值”,而 Is... 正在解包。尾随 ... 导致使用 Is 的表达式解包。我还是不明白。请解释更多:)
  • @J.Doe 添加了一个可以编译的示例 (c++14)。希望内联 cmets 可以帮助您入门。
猜你喜欢
  • 2011-09-28
  • 1970-01-01
  • 2012-11-05
  • 1970-01-01
  • 2016-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多