std :: tie는 어떻게 작동합니까?


120

나는 그것에 std::tie대해 많이 생각하지 않고 사용 했습니다. 작동하므로 다음을 수락했습니다.

auto test()
{
   int a, b;
   std::tie(a, b) = std::make_tuple(2, 3);
   // a is now 2, b is now 3
   return a + b; // 5
}

하지만이 흑 마법 은 어떻게 작동합니까? 어떻게 일시적인가 만든 않습니다 std::tie변화 ab? 나는 이것이 언어 기능이 아니라 라이브러리 기능이기 때문에 더 흥미 롭다는 것을 알게되었고, 확실히 우리가 스스로 구현하고 이해할 수있는 것입니다.

답변:


152

핵심 개념을 명확히하기 위해 좀 더 기본적인 예를 들어 보겠습니다. std::tie더 많은 값 (튜플)을 반환하는 함수에 유용 하지만 하나의 값으로도 잘 이해할 수 있습니다.

int a;
std::tie(a) = std::make_tuple(24);
return a; // 24

앞으로 나아 가기 위해 알아야 할 사항 :

  • std::tie 참조의 튜플을 구성하고 반환합니다.
  • std::tuple<int>그리고 std::tuple<int&>그들은 같은 템플릿에서 생성 된 것을 다른 이들 사이에 연결이 완전히 다른 클래스는,,,이다 std::tuple.
  • 튜플은 operator=서로 다른 유형 (하지만 동일한 번호)의 튜플을 받아들이고 각 멤버는 cppreference 에서 개별적으로 할당됩니다 .

    template< class... UTypes >
    tuple& operator=( const tuple<UTypes...>& other );
    

    (3) 모든 i에 std::get<i>(other)대해 std::get<i>(*this).

다음 단계는 방해가되는 함수를 제거하는 것이므로 코드를 다음과 같이 변환 할 수 있습니다.

int a;
std::tuple<int&>{a} = std::tuple<int>{24};
return a; // 24

다음 단계는 해당 구조 내부에서 일어나는 일을 정확히 확인하는 것입니다. 이를 위해 두 가지 유형의 T치환기 std::tuple<int>Tr치환기 std::tuple<int&>를 생성하고 작업을 위해 최소한으로 줄였습니다.

struct T { // substituent for std::tuple<int>
    int x;
};

struct Tr { // substituent for std::tuple<int&>
    int& xr;

    auto operator=(const T& other)
    {
       // std::get<I>(*this) = std::get<I>(other);
       xr = other.x;
    }
};

auto foo()
{
    int a;
    Tr{a} = T{24};

    return a; // 24
}

마지막으로 저는 구조를 모두 제거하는 것을 좋아합니다 (100 % 동등하지는 않지만 우리에게 충분히 가까우며 허용 할 수있을만큼 명시 적입니다).

auto foo()
{
    int a;

    { // block substituent for temporary variables

    // Tr{a}
    int& tr_xr = a;

    // T{24}
    int t_x = 24;

    // = (asignement)
    tr_xr = t_x;
    }

    return a; // 24
}

따라서 기본적으로 std::tie(a)데이터 멤버 참조를 a. std::tuple<int>(24)value가있는 데이터 멤버를 만들고 24할당은 첫 번째 구조의 데이터 멤버 참조에 24를 할당합니다. 그러나 해당 데이터 멤버는에 바인딩 된 참조 a이므로 기본적으로에 할당 24됩니다 a.


1
저에게 버그는 할당 연산자를 rvalue로 호출한다는 것입니다.
Adam Zahran

답변 에서는 컨테이너가 참조를 보유 할 수 없다고 명시했습니다. 왜 tuple참조를 가질 수 있습니까?
nn0p

6
@ nn0p std::tuple는 컨테이너가 아닙니다. 적어도 C ++ 용어에는 포함되어 있지 않습니다 std::vector. 예를 들어 튜플에는 다른 유형의 객체가 포함되어 있기 때문에 일반적인 방법으로 반복 할 수 없습니다.
bolov

@Adam tie (x, y) = make_pair (1,2); 실제로 표준 : 타이 (x, y)를 .operator =이된다 (표준 : make_pair (1, 2))의 "를 rvalue에 할당"XD 작동하는 이유는, 그것의
후아 조각

30

이것은 어떤 식 으로든 귀하의 질문에 대답하지 않지만 C ++ 17이 기본적으로 준비되어 있기 때문에 (컴파일러 지원 포함) 어쨌든 게시하겠습니다. 구식 항목이 어떻게 작동하는지 궁금하지만 현재 상태를 살펴볼 가치가 있습니다. 미래에는 C ++ 버전도 작동합니다.

C ++ 17을 사용하면 구조적 바인딩std::tie 이라고하는 것을 선호 할 수 있습니다 . 동일한 기능을 수행합니다 (글쎄요, 동일 하지는 않지만 동일한 효과가 있습니다). 더 적은 수의 문자를 입력해야하지만 라이브러리 지원이 필요하지 않으며 참조를받을 수있는 기능 있습니다. 당신이 원하는 것.

(C ++ 17에서 생성자는 인수 추론을 수행하므로 make_tuple다소 불필요 해졌습니다.)

int a, b;
std::tie(a, b) = std::make_tuple(2, 3);

// C++17
auto  [c, d] = std::make_tuple(4, 5);
auto  [e, f] = std::tuple(6, 7);
std::tuple t(8,9); auto& [g, h] = t; // not possible with std::tie

2
마지막 줄이 컴파일되면 조금 걱정됩니다. 불법적 인 임시 참조를 바인딩하는 것처럼 보입니다.
Nir Friedman

3
@Neil rvalue 참조이거나 const lvalue 참조 여야합니다. lvalue 참조를 prvalue (임시)에 바인딩 할 수 없습니다. 이것은 MSVC에서 오랫동안 "확장"되었습니다.
Nir Friedman

1
tie기본적으로 구성 할 수없는 유형에 대해 이와 달리 구조화 된 바인딩을 이러한 방식으로 사용할 수 있다는 점도 언급 할 가치가 있습니다.
Dan

5
예, std::tie()구조화 된 바인딩이 일반적으로 우월한 C ++ 17 이후로 훨씬 덜 유용하지만 기존 (동시에 새로 선언되지 않은) 변수에 할당하고 여러 변수를 스왑하는 것과 같은 다른 작업을 간결하게 수행하는 등 여전히 사용됩니다. 참조에 할당해야합니다.
underscore_d
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.