2012-11-24 4 views
2

가변성 템플릿 덕분에 파이썬의 체인 함수와 비슷한 C++을 구현했습니다. 이 함수는 여러 컨테이너를 연속적으로 반복하는 데 사용됩니다.variadic 템플릿 템플릿을 사용한 타입 공제와 인수 전달

template<typename... Iterables> 
auto chain(Iterables&&... iters) 
    -> ChainObject<Iterables...> 
{ 
    return /* ... */; 
} 

그리고 해당 주 :

int main() 
{ 
    std::vector<int> vec = { 1, 2, 3, 4, 5 }; 
    std::list<int> li = { 6, 7, 8, 9, 10, 11, 12, 13 }; 
    for (auto& i: chain(vec, li)) 
    { 
     // You can edit a range of iterables 
     // as if there was only one of them. 
     i *= 5; 

     std::cout << i << std::endl; 
    } 
    return 0; 
} 

주요 잘 작동하는지 여기가 어떤 ChainedObject라는 생성기를 사용하여 함수의 이전 작업 버전입니다. 우리는 ChainObject에있는 문제가 무엇인지 상관하지 않습니다. 그래서 봅시다. 내가 사용하는 다른 컬렉션이 같은 value_type을 한 것으로 확인 템플릿 템플릿을 사용하려고 다음과 같은 방법으로 기능 chain 수정 :

template<typename T, template<typename...> class... Iterables> 
auto chain(Iterables<T>&&... iters) 
    -> ChainObject<T, Iterables...> 
{ 
    return /* ... */; 
} 

나는 이것이 내 이전 주에서 listvector을 보장하기 위해 트릭을 할 것이라고 생각 동일한 유형을 공유하지만 대신에, 나는 GCC 4.7.1에서 다음과 같은 오류 얻을 :

In function 'int main()':

error: no matching function for call to 'chain(std::vector&, std::list&)'

note: candidates are:

note: ChainObject<T, Iterables ...> chain(Iterables<T>&& ...) [with T = int; Iterables = {std::vector, std::list} ]

note: no known conversion for argument 2 from ' std::list<int> ' to ' std::list<int>&& '

note: ChainObject<T, Iterables ...> chain(Iterables<T>&& ...) [with T = int; Iterables = {std::vector, std::list}]

note: no known conversion for argument 2 from ' std::list<int> ' to ' std::list<int>&& '

error: unable to deduce 'auto&' from ''

문제를 rvalue 참조를 복용 함수에 전달 인자에서 오는 것으로 보인다합니다. 그러나, 나는 왜 나의 첫번째 버전이 잘 작동하는지 이해하지 못하고, 템플릿 템플릿을 사용하는 것에 주목한다.

+0

는 당신이를 rvalue 대신 좌변 참조를 전달하는 시도? –

+0

템플릿 템플릿을 컨테이너와 함께 사용하지 마십시오. 할당자가 사용되는 즉시 실패 할 것입니다. 그냥 중첩 된'value_type'의 동등성을 검사하십시오. – pmr

답변

5

T&& 템플릿 매직은 유형 매개 변수에서만 작동합니다 (이는 T을 예를 들어, int&, 즉 좌측 값 인수로 추론하여 작동 함). 실제 템플릿 파일 형식은 X<T>&&입니다. X은 "class-reference-template"과 같은 것이 아니라이 경우 클래스 템플릿이어야합니다. 그래서 마지막에 좌변 값 (변수)에서 내재적으로 얻을 수없는 rvalue-reference를 전달해야합니다.

SFINAE를 사용하면 이전 코드로 되돌아 가서 value_type이 동일한 지 (또는 호환 여부 등) 확인할 수 있습니다. (완전 항등에 대한)

거친 코드 스케치 :

template <class ... Ts> struct all_types_equal 
{ 
    static const bool value = false; 
}; 

template <class T> 
struct all_types_equal<T> 
{ 
    static const bool value = true; 
}; 
template <class T, class ... Rest> 
struct all_types_equal<T, T, Rest...> 
{ 
    static const bool value = all_types_equal<T, Rest...>::value; 
}; 

template<typename... Iterables> 
auto chain(Iterables&&... iters) 
    -> typename std::enable_if<all_types_equal<Iterable::value_type...>::value, ChainObject<Iterables...> >::type 
+0

고맙습니다. 그것은 C++에 대해 아직도 배울 점이 많습니다. 나는 보통의'enable_if'를 사용하여 되돌릴 것이다. – Morwenn

+0

올바른 리턴 타입은'typename std :: enable_if :: type :: value_type ...이다. > :: value, ChainObject > :: type'을 반환합니다. – Morwenn

관련 문제