2013-06-18 4 views
4

std::get<N>(std::tuple) 메쏘드를 직접 만들려고 시도한 후에 컴파일러에 의해 어떻게 구현되는지 잘 모르겠습니다. 나는 std::tuple이 같은 생성자가std ::는 어떻게 작동합니까?

tuple(Args&&... args); 

알고 있지만 정확히 args...가 할당된다? 나는 이것들이 어떻게 접근하는지 알기 위해서 유용하다고 생각한다 ...

+4

당신이 부스트 :: get''쳐다 보면서'부스트 : tuple' 있습니다

그리고 마지막으로, 몇 가지 기본적인 테스트 코드

? 'std :: get'이 구현 된 헤더 파일은 어떻습니까? * 읽기 쉽지는 않지만 대개 C++ 에서처럼 구현됩니다. (이 표준은 표준 라이브러리가 C++로 구현 될 것을 요구하지 않습니다) – Yakk

답변

6

다음은 tuple과 같은 클래스의 조잡한 장난감 구현이다.

첫째, 일부 메타 프로그래밍 상용구는 정수 시퀀스 나타내는데 :

template<int...> struct seq {}; 
template<int max, int... s> struct make_seq:make_seq< max-1, max-1, s... > {}; 
template<int... s> struct make_seq<0, s...> { 
    typedef seq<s...> type; 
}; 
template<int max> using MakeSeq = typename make_seq<max>::type; 

다음에, 실제 데이터를 저장하는 태그 클래스 :

template<int x, typename Arg> 
struct foo_storage { 
    Arg data; 
}; 

이 태그 기술은 일반적인 패턴마다이며 우리는 컴파일 타임에 어떤 태그 (이 경우에는 정수)와 데이터를 연관시키고 자한다. 태그 (여기 int)는 일반적으로 저장소의 어느 곳에서나 사용되지 않고 저장소에 태그하는 데 사용됩니다.

foo_helper은 일련의 인수를 묶음 foo_storage에 압축 해제 한 다음 선형 형식으로 상속합니다. 이것은 매우 일반적인 패턴이다 -이 많이하고 있다면, 당신은 당신을 위해 이렇게 메타 프로그래밍 도구를 만들어 결국 :

template<typename Seq, typename... Args> 
struct foo_helper {}; 
template<int s0, int... s, typename A0, typename... Args> 
struct foo_helper<seq<s0, s...>, A0, Args...>: 
    foo_storage<s0, A0>, 
    foo_helper<seq<s...>, Args...> 
{}; 

내 원유 tuple 유형, foo는, 인덱스의 순서의 패키지를 만듭니다 args를 가져 와서 위의 도우미에게 전달합니다. 이 get을 구현하는 데 필요한되지 않기 때문에,

template<typename... Args> 
struct foo: foo_helper< MakeSeq<sizeof...(Args)>, Args... > {}; 

내가 foo의 몸에서 모든 것을 제거 : 도우미는 태그 데이터 잡고 부모 클래스의 무리를 만듭니다. 우리는 저장 유형 (안 튜플 타입)을 가지고, 그리고 foo_storage<n, T>의 우리가 가고있는 명시 적 template 인수 N들의 차이는 액세스 할 :

get은 아주 간단합니다. 우리는 무거운 작업을 수행 할 C++ langauge의 과부하 메커니즘을 사용하는

template<int N, typename T> 
T& get(foo_storage<N, T>& f) 
{ return f.data; } 
template<int N, typename T> 
T const& get(foo_storage<N, T> const& f) 
{ return f.data; } 

: 이제 우리는 스토리지 유형을 가지고, 우리는 단순히 데이터 필드를 반환합니다. 클래스 인스턴스가있는 함수를 호출 할 때 각 부모 클래스가 해당 인스턴스로 이동하여 해당 인스턴스 중 하나라도 일치시킬 수 있는지 확인합니다. N을 수정하면 올바른 인수 인 부모 클래스가 하나만 있으므로 부모 클래스 (따라서 T)가 자동으로 추론됩니다.

#include <iostream> 

int main() { 
    foo<int, double> f; 
    get<0>(f) = 7; 
    get<1>(f) = 3.14; 
    std::cout << get<0>(f) << "," << get<1>(f) << "\n"; 
} 
+3

이것은 엄청나게 향상 될 수 있습니다. 예를 들어 [이 장난감 구현] (http : // coliru.stacked-crooked.com/view?id=d51ff6c809c9d6fabede11d0fa67a19a-f0d9bbac4ab033ac5f4ce440d21735ee) 전 몇 시간 전에 썼습니다. 파생 - 기반 변환에 의존하며 기본 유형 (즉, 색인)의 일부를 지정하여 강제 변환합니다. – Xeo

+0

@Xeo가 고정되어'int (*) [N]'해킹이 제거되었습니다. – Yakk