태그 보관물: iteration

iteration

std :: tuple의 요소를 어떻게 반복 할 수 있습니까? 수 있습니까? 다음을 시도했습니다. for(int i=0;

튜플 (C ++ 11 사용)을 어떻게 반복 할 수 있습니까? 다음을 시도했습니다.

for(int i=0; i<std::tuple_size<T...>::value; ++i)
  std::get<i>(my_tuple).do_sth();

그러나 이것은 작동하지 않습니다.

오류 1 : 죄송합니다. 구현되지 않았습니다. ‘Listener …’를 고정 길이 인수 목록으로 확장 할 수 없습니다.
오류 2 : 상수 표현식에 나타날 수 없습니다.

그렇다면 튜플의 요소를 올바르게 반복하는 방법은 무엇입니까?



답변

Boost.Fusion 은 가능성이 있습니다.

테스트되지 않은 예 :

struct DoSomething
{
    template<typename T>
    void operator()(T& t) const
    {
        t.do_sth();
    }
};

tuple<....> t = ...;
boost::fusion::for_each(t, DoSomething());


답변

튜플 에 대한 반복을 기반으로 한 답변이 있습니다 .

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

template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
  print(std::tuple<Tp...>& t)
  { }

template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
  print(std::tuple<Tp...>& t)
  {
    std::cout << std::get<I>(t) << std::endl;
    print<I + 1, Tp...>(t);
  }

int
main()
{
  typedef std::tuple<int, float, double> T;
  T t = std::make_tuple(2, 3.14159F, 2345.678);

  print(t);
}

일반적인 아이디어는 컴파일 시간 재귀를 사용하는 것입니다. 사실,이 아이디어는 원본 튜플 문서에서 언급 한 것처럼 형식이 안전한 printf를 만드는 데 사용됩니다.

이것은 for_eachfor tuples 로 쉽게 일반화 될 수 있습니다 :

#include <tuple>
#include <utility>

template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
  for_each(std::tuple<Tp...> &, FuncT) // Unused arguments are given no names.
  { }

template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
  for_each(std::tuple<Tp...>& t, FuncT f)
  {
    f(std::get<I>(t));
    for_each<I + 1, FuncT, Tp...>(t, f);
  }

그러면 FuncT튜플이 포함 할 수있는 모든 유형에 대해 적절한 오버로드로 무언가를 나타 내기 위해 약간의 노력이 필요 합니다. 이것은 모든 튜플 요소가 공통 기본 클래스 또는 유사한 것을 공유한다는 것을 알고있는 경우 가장 잘 작동합니다.


답변

C ++ 17에서는 접기 표현식std::apply 과 함께 사용할 수 있습니다 .

std::apply([](auto&&... args) {((/* args.dosomething() */), ...);}, the_tuple);

튜플을 인쇄하는 완전한 예 :

#include <tuple>
#include <iostream>

int main()
{
    std::tuple t{42, 'a', 4.2}; // Another C++17 feature: class template argument deduction
    std::apply([](auto&&... args) {((std::cout << args << '\n'), ...);}, t);
}

[Coliru의 온라인 예]

이 솔루션은 M. Alaggan의 답변 에서 평가 순서 문제를 해결합니다 .


답변

C ++ 17에서는 다음을 수행 할 수 있습니다.

std::apply([](auto ...x){std::make_tuple(x.do_something()...);} , the_tuple);

이것은 std :: experimental :: apply를 사용하여 Clang ++ 3.9에서 이미 작동합니다.


답변

Boost.Hana 및 일반 람다 사용 :

#include <tuple>
#include <iostream>
#include <boost/hana.hpp>
#include <boost/hana/ext/std/tuple.hpp>

struct Foo1 {
    int foo() const { return 42; }
};

struct Foo2 {
    int bar = 0;
    int foo() { bar = 24; return bar; }
};

int main() {
    using namespace std;
    using boost::hana::for_each;

    Foo1 foo1;
    Foo2 foo2;

    for_each(tie(foo1, foo2), [](auto &foo) {
        cout << foo.foo() << endl;
    });

    cout << "foo2.bar after mutation: " << foo2.bar << endl;
}

http://coliru.stacked-crooked.com/a/27b3691f55caf271


답변

C ++는 이를 위해 확장 문 을 도입 하고 있습니다. 그들은 원래 C ++ 20을위한 궤도에 있었지만 언어 표현 검토를위한 시간 부족으로 간신히 컷을 놓쳤습니다 ( 여기여기 참조 ).

현재 합의 된 구문 (위 링크 참조)은 다음과 같습니다.

{
    auto tup = std::make_tuple(0, 'a', 3.14);
    template for (auto elem : tup)
        std::cout << elem << std::endl;
}


답변

C ++ 17에서이 작업을 수행하는보다 간단하고 직관적이며 컴파일러 친화적 인 방법은 다음과 if constexpr같습니다.

// prints every element of a tuple
template<size_t I = 0, typename... Tp>
void print(std::tuple<Tp...>& t) {
    std::cout << std::get<I>(t) << " ";
    // do things
    if constexpr(I+1 != sizeof...(Tp))
        print<I+1>(t);
}

이것은 @emsr이 제시 한 것과 유사한 컴파일 타임 재귀입니다. 그러나 이것은 SFINAE를 사용하지 않으므로 (제 생각에) 컴파일러 친화적입니다.