变种模板。一些问题

时间:2016-04-27 16:45:24

标签: c++ c++11

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<T_value...>())
  2. 为什么在yadda(std::get<Is>(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<Is...>。 毕竟,这个论点是无名的,所以它没用。我认为它与演绎类型有关,但我看不出它有什么帮助?

1 个答案:

答案 0 :(得分:2)

  

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

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

std::index_sequence<0, 1, 2>
  

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

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

  

特别是,哪个std :: get适合于(1) - (8)(http://en.cppreference.com/w/cpp/utility/tuple/get

在这种情况下,元组引用为const std::tuple<T_values...>&,因此它将为3。

  

为什么call_yadda_with_tuple获取std :: index_sequence。毕竟,这个论点是无名的,所以它没用。我想它与演绎类型有关,但我看不出它有什么帮助呢?

只会导致Is...存在,因此您可以扩展序列中的所有Is

编辑:

以下是一个评论示例,希望能够解释正在发生的事情

#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