2017-12-31 50 views
2

컬렉션의 표준 출력 범위를 인쇄하는 보편적 인 함수를 작성하고 싶습니다. 그것은 보편적 있어야하기 때문에 나는 가정템플릿 인수의 형식을 지정하는 방법 STL 반복자 형식

std::vector<std::string> names = { "John", "Henry", "Mark" }; 

뿐만 아니라 ... 그 :

std::vector<int> years = { 100, 200, 400 }; 

.. 인쇄 할 수있을 것입니다.

수집의 종류가 다를 수 있습니다, 그리고 나에게 내가 템플릿 기능을 사용하여 기본 클래스의 반복자를 전달하는 기회를 제공하는 STL 수집을위한 기본 클래스가 없기 때문에 :

template<typename TIterator> 
void PrintRange(TIterator beginIter,TIterator endIter) 
{   
    for(auto it = beginIter; it != endIter; ++it) 
    { 
     std::cout << *it << std::endl; 
    } 
} 

모든 것이 지금 잘 작동이, 지금은 쓸 수 있습니다 :

PrintRange(names.begin(), names.end()); 

과 :

PrintRange(years.begin(), years.end()); 

하지만 지금은 그가 원하는 lp 클라이언트가 내 기능을 사용하면 오류가 발생하는 이유를 빨리 이해할 수 있습니다. 지금은 전화 할 때 :

main.cpp:23:34: error: invalid type argument of unary ‘*’ (have ‘int’)

내가 좋아하는 뭔가를 인쇄하고 싶습니다 :

PrintRange(100, 400); 

오류가 있습니다

One of arguments does not correspond to expected argument of type 'iterator'

그래서이 문제에 어떻게 접근 방식은 최고 :

  1. 걱정하지 않아도됩니다. 오류 메시지는 내가 예상 한대로 의미가있는 이 아닙니다. 사용자는 템플릿 클래스 코드를 으로 분석하여 실수의 원인을 확인해야합니다.

  2. 모든 가능한 가능성을 주장하기 위해 static_assert를 사용합니다.하지만 기본 클래스가 없으므로 function의 인수가 반복자임을 주장하는 방법은 무엇입니까?

static_assert(std::is_base_of::iterator >::value);

이는 문자열 반복자의 벡터를 주장하는 것입니다 ...

+0

왜 다른 유형의 시작과 끝 반복자입니까? 그것들은 같은 것이어야합니다 – Fureeish

+0

함수에 좋은 문서를 추가하면 사용자는 템플릿 코드를 검사 할 필요가 없으며 입력의 유효성 검사에 추가 작업을 할 필요가 없습니다. 컴파일러가 유효하게합시다! –

답변

2

개인적으로, 나는 당신이 추가 오류 메시지에 대한 많은 관심이되지 않을 수도 있습니다 첫 번째 접근 방식은 완전히 괜찮라고 생각합니다.

한편, 의미있는 메시지를 인쇄하기로 결정한 경우 here으로 설명한 이터레이터를 검색하기위한 사용자 지정 형식 특성을 구현 한 다음 static_assert과 함께 사용하십시오. 그래서 코드가 같은으로 변환 : 에드가 Rokyan에서 제공

template<typename TIterator> 
void PrintRange(TIterator beginIter, TIterator endIter) 
{   
    static_assert(is_iterator<TIterator>::value, 
     "TIterator is not an iterator type"); 

    for(auto it = beginIter; it != endIter; ++it) 
    { 
     std::cout << *it << std::endl; 
    } 
} 
0

대답하는 것은 매우 도움이 될 것입니다,하지만 난 다른 해결책 알고있다 (아마 우리가 더 많은 코드를 구현해야하기 때문에, 하나 더 나쁜).

이 솔루션은 반복기에 대한 유형 검사가 아니라 방향을 제시하는 힌트입니다.PrintRange 함수를 가정하면 TIterator - operator*, operator++operator !=에 대해 3 개의 연산자가 정의되어야한다고 가정합니다.

은이를 사용할 수 있습니다, 운영자가 정의되어 있는지 여부를 확인하려면 다음

template<typename T> 
struct has_deref_op{ 
    private: 
     template<typename U> 
     static constexpr auto test(int) -> decltype(std::declval<U>().operator*() == 1, 
                std::true_type()); 

     template<typename U> 
     static constexpr std::false_type test(...); 

    public: 
     static constexpr bool value = std::is_same<decltype(test<T>(0)), 
                std::true_type>::value; 
}; 

이 코드는 T 구현 operator*의 존재를 확인합니다. 그런 다음 순서로 사용하는 static_assert 인수를 검증하기 위해 추가 할 수 있습니다

template<typename TIterator> 
void PrintRange(TIterator beginIter, TIterator endIter) 
{ 
    static_assert(has_deref_op<TIterator>::value, "argument must implement operator*"); 
    for(auto it = beginIter; it != endIter; ++it) 
    { 
     std::cout << *it << std::endl; 
    } 
} 

이 솔루션은 주요 결함을 가지고 - 그것은 오류 메시지를 단순화하기 위해 코드를 꽤 많이 작성해야합니다. 솔직하게 말해서,이 접근법은 꽤 잘 작동하지만, 나는 디폴트 에러 메시지를 고수 할 것이다. 이는 자명 한 것입니다. operator*이 정의되어 있지 않은 int을 제공하면 오류가 발생합니다.

편집 : Edgar가 자신의 대답에서 링크 한 질문을 읽은 후이 방법과 비슷하게 적용 할 is_iterator을 구현하는 것이 좋습니다. 신중하게 처음으로 읽지 않는 것에 대한 나쁨

관련 문제