구현 목록
• iterators_traits
• enable_if
• is_integral
• equal
• lexicographical_compare
• SFINAE
요구 사항
• namespace 만들기
• std::allocator
• friend
반복자 특질?
원래는 iterator_traits
인데 서브젝트에는 iterators_traits
라고 표기가 되어 있다.
cplusplus에 따르면 iterator_traits
는 반복자의 속성을 정의하는 반복자 클래스라고 한다.
반복자 관점에서 알고리즘을 구현하게 할 수 있다.
아래는 해당 페이지의 파파고 버전
표준 알고리즘은 전달된 반복자의 특정 특성과 해당 iterator_traits 인스턴스화의 멤버를 사용하여 나타내는 범위를 결정한다.
모든 반복자 유형에 대해 iterator_traits 클래스 템플릿의 해당 전문화를 정의해야 하며, 적어도 다음 멤버 유형을 정의해야 한다.
참고: 적어도 순방향 반복자가 아닌 출력 반복자의 경우, 이러한 멤버 유형 중 하나('itator_category' 제외)는 void로 정의될 수 있습니다.
'iterator_traits' 클래스 템플릿은 이러한 유형을 반복자 유형 자체에서 가져오는 기본 정의와 함께 제공됩니다(아래 참조). 또한 pointer (T)와 const(const T)에 특화되어 있다.
모든 사용자 지정 클래스는 기본 클래스 std::iterator를 공개적으로 상속하는 경우 'iterator_trates'의 유효한 인스턴스화를 가집니다.
멤버 | 일반적 정의 | T* 특수화 | const T* 특수화 |
---|---|---|---|
difference_type | Iterator::difference_type | ptrdiff_t | ptrdiff_t |
value_type | Iterator::value_type | T | T |
pointer | Iterator::pointer | T* | const T* |
reference | Iterator::reference | T& | const T& |
iterator_category | Iterator::iterator_category | random_access_iterator_tag | random_access_iterator_tag |
SFINAE
는 Substitution Failure Is Not An Error
의 약어이다.
이 기능은 TMP에서 사용이 되는데, 템플릿으로 오버로딩 함수를 만들었을때 만약 인자 치환이 실패했을 경우 컴파일러는이 오류를 무시하고 오버로딩 후보에서 제외한다는 의미이다.
하지만 매번 컴파일 오류가 무시되는 것은 아니다. SFINAE
는 적용범위가 한정되어 있다.
대표적인? SFINAE 유형
c++11이후에 추가된 것으로 enable_if
를 사용하면 SFINAE
를 잘 사용할 수 있게 된다.
enable_if
는 오버로딩 확인을 위한 형식의 인스턴스를 조건부를 만든다. enable_if
를 사용하게 되면 수많은 오버로딩 템플릿들의 치환오류를 탐색하고 오류가 날 경우 오버로딩 후보군에서 제거해주는 역할을 하기 때문이다.
template <class T, typename std::enable_if<std::is_integral<T>::value, T>::type * = 0>
void test(T &a)
{
std::cout << "is int" << std::endl;
}
이런식으로 정의해주면 인자로 정수값이 들어왔을때만 해당 오버로딩 함수가 실행된다고 한다.
T가 정수유형인지 여부를 식별하는 구조체 템플릿이다.
T의 정수 유형 여부에 따라 true_type, false_type으로 상속된다.
멤버 타입으로는
멤버 변수는 참인지 거짓인지 구분하는 bool타입의 value가 하나 있다.
두 범위의 요소가 같은지 확인하는 함수이다.
두 범위의 요소가 같으면 true를 아니면 flase를 리턴한다.
두 요소가 동일하지 않을 때 사전순으로 비교하게 해주는 함수이다.
아마 map구현에 사용이 될 것 같은 함수이다.
namespace [namespace name]
{
class [class]
{
...
};
};
[namespace name]::[class name]::myFunc() { ... };
이런식으로 헤더와 cpp파일을 작성하면
#include "myHeader.hpp"
int main()
{
[namespace]::[class] a;
}
이렇게 해당 namespace에 있는 class를 불러와 객체를 만들수 있게된다!
일반적으로 동적할당을 할때는 new 와 delete 를 사용하는데 STL이나 라이브러리를 작성할때는 allocator를 많이 사용한다고 한다.
메모리를 좀더 유연하고 효율적으로 사용하기 위해 allocator클래스를 상속받아 멤버함수를 오버라이드해 커스텀한다고 한다.
그래서 컨테이너들은 대부분 allocator를 사용하여 메모리를 관리한다고 한다.
뿐만 아니라 아래와 같은 장점도 지니고 있다.
friend
가 붙은 클래스가 friend
로 선언된 다른 클래스의 private및 protected멤버에 접근 할 수 있게 해주는 키워드이다.
그런데 클래스말고 함수에도 이 키워드를 붙일 수 있다.
멤버 함수 단위로 지정을 해주게 되면 이미 정의되어 있는 함수를 자신의 클래스에 정의만 해서 사용할 수 있게 되는 것이다.
friend키워드를 명시하지 않는 이상 친구 관계가 형성되지 않고,
이미 친구 관계를 형성한 클래스의 자식 클래스고 키워드를 명시하지 않으면 친구 관계가 형성되지 않는다.
참고 사이트