반응형
이전 글에서는 책임 연쇄(Chain of Responsibility) 패턴을 모던 C++ 관점에서 재해석하며, 상속 없이 람다와 함수 합성, std::expected, coroutine, Ranges, std::format 등을 활용해 요청 처리 파이프라인을 단순하고 유연하게 구현할 수 있음을 확인했습니다. 이제는 행동(Behavioral) 패턴 중 상태(State) 패턴을 다룹니다.상태 패턴은 객체가 내부 상태에 따라 서로 다른 행동을 수행하도록 하는 패턴입니다. 전통적으로는 State 인터페이스, ConcreteState 클래스를 상속해 상태별로 다른 메서드를 오버라이드하고, 상태 전이 시 상태 객체 교체 방식으로 구현했습니다. 이는 새로운 상태 추가 시 클래스 증가, 상태 전이 로직 분산, 유지보수..
이전 글까지 우리는 대부분의 GoF 패턴을 모던 C++ 관점에서 재해석해왔습니다. 이번에는 행동(Behavioral) 패턴 중 아직 다루지 않은 책임 연쇄(Chain of Responsibility) 패턴에 주목합니다.책임 연쇄 패턴은 한 요청이 처리될 수 있는 핸들러를 체인 형태로 연결하고, 요청이 들어오면 체인을 따라가며 처리 가능 한 핸들러를 찾는 구조를 만듭니다. 전통적으로는 핸들러 인터페이스와, setNextHandler() 메서드를 통해 다음 핸들러를 연결하는 구조를 취했지만, 이는 상속 기반 설계로 인한 클래스 증가와 유지보수 어려움을 야기합니다.C++20 이상에서는 Concepts로 요청/응답 인터페이스를 제약하고, 람다와 함수 합성으로 핸들러를 정의해 상속 없이 체인을 구성할 수 있습니다..
이전 글에서는 플라이웨이트(Flyweight) 패턴을 모던 C++ 관점에서 재해석하며, 상속 없이 값 기반 공유 로직을 단순히 구현하고, 조건부 처리, 비동기 로딩, 로깅, 에러 처리 등 다양한 요구에도 쉽게 대응할 수 있음을 확인했습니다. 이번에는 구조적 패턴 중 프록시(Proxy) 패턴을 다룹니다.프록시 패턴은 객체 접근을 제어하거나, 지연 로딩(Lazy Loading), 원격 호출(Remote Proxy), 캐싱(Caching), 권한 체크 등의 기능을 대리 객체를 통해 투명하게 추가하는 패턴입니다. 전통적으로는 상속 기반 인터페이스와 Proxy 클래스를 정의해 접근 로직을 구현했으나, 이는 클래스 증가, 유지보수 어려움, 에러 처리나 비동기 처리 시 복잡성을 초래합니다.C++20 이상에서는 Con..
C++ 템플릿과 메타프로그래밍은 코드 재사용성과 추상화의 강력한 수단이지만, 복잡하고 장황해지기 쉽습니다. C++20 Concepts를 도입함으로써 타입 제약을 명확히 표현할 수 있지만, 이 또한 스타일 유지에 도전 과제를 던집니다. 템플릿 파라미터 리스트의 길고 난해한 선언, SFINAE를 통한 조건부 활성화 코드, 개별 trait 구조체나 헬퍼 템플릿의 무질서한 배치 등은 코드 가독성을 해칠 수 있습니다.이번 글에서는 구글 C++ 스타일 가이드, LLVM 스타일 가이드, 모질라 스타일 가이드 등에서 언급하는 템플릿 및 메타프로그래밍 관련 스타일 이슈를 살펴봅니다. 또한 Concepts를 활용하는 방법, SFINAE 대신 Concepts를 사용하는 접근, 템플릿 파라미터 정렬, trait 정의 분리, ..
과거 C++ 템플릿 프로그래밍에서 타입 제약을 표현하기 위해 사용되던 기법 중 하나가 바로 SFINAE(Substitution Failure Is Not An Error)였습니다. 이는 템플릿 인자의 대입 과정에서 타입이 맞지 않을 경우 에러 대신 다른 오버로드를 시도하는 기법으로, 조건부로 템플릿을 선택하는 메타프로그래밍 트릭이었습니다.그러나 SFINAE는 코드가 복잡해지고, 컴파일 에러 메시지가 난해해진다는 단점이 있었습니다. 모던 C++20에서는 Concepts를 통해 이 문제를 해결했습니다. Concepts는 템플릿 인자에 대한 명확한 제약 조건을 선언적으로 표현할 수 있어 코드 가독성과 유지보수성, 그리고 에러 진단을 크게 개선합니다.관련 참고 자료:SFINAEConcepts (C++20)과거:..
앞서 기본 구현을 통해 groupby, permutations, product를 C++로 옮기는 방법을 살펴봤습니다. 여기서는 C++20의 Concepts와 Ranges 라이브러리를 활용해 정교한(또는 확장된) 구현 방법을 간단히 예시로 보여드리겠습니다.파이썬스럽다는 것은 단순히 기능을 흉내내는 데 그치지 않고, 타입 안정성, 가독성, 모듈성까지 고려하는 것입니다. Concepts로 입력 타입을 제약하거나, Variadic Template로 product를 여러 컨테이너에 확장하는 예제를 살펴보죠.정교한(또는 확장된) 구현 예제1. groupby에 Concepts 적용하기groupby는 연속된 원소를 key 함수 결과에 따라 그룹화합니다. 여기서 key 함수는 원소를 받아 어떤 key로 매핑하는 Call..
이제까지 파이썬 itertools와 more-itertools의 다양한 함수를 C++로 옮기며, 현대 C++이 제공하는 Ranges, Concepts, lazy evaluation을 통해 얼마나 파이썬스러운 코드를 구현할 수 있는지 확인했습니다. 이번에는 takewhile, dropwhile, 그리고 accumulate를 C++에서 흉내 내는 방법을 살펴보겠습니다.먼저 파이썬에서 이 함수들이 어떻게 동작하는지 간단히 살펴볼까요?from itertools import takewhile, dropwhile, accumulate# takewhile(predicate, iterable)# predicate가 참인 동안만 원소를 반환하다가, 거짓이 되는 순간 멈춤data = [1,2,3,4,5,1,2]for x ..
그동안 다양한 itertools 기능을 C++로 옮기는 방법을 살펴봤습니다. 파이썬 itertools는 시퀀스를 다루는 멋진 아이디어를 끊임없이 제공하는데, 이번에는 chain.from_iterable와 batched 두 가지를 살펴보려 합니다. 특히 batched는 파이썬 3.11에서 새롭게 추가된 함수로, 이 역시 매력적인 기능입니다. 먼저 파이썬에서 이 두 함수를 간단히 소개해볼게요.from itertools import chain, batched# chain.from_iterable(iterable_of_iterables)는 이중 iterable을 평탄화# 예: [[1,2],[3,4,5],[6]] -> 1,2,3,4,5,6list_of_lists = [[1,2],[3,4,5],[6]]for x i..
우리가 지금까지 다룬 파이썬 itertools 함수들 외에도, 파이썬에서 제공하는 편리한 반복 툴이 여전히 많이 남아 있습니다. 이번 글에서는 그중에서도 자주 쓰이는 세 가지를 골라봤습니다. 먼저, 파이썬으로 몇 가지 예제를 보여드릴게요:from itertools import count, zip_longest, pairwise# count는 start부터 step 간격으로 무한히 증가하는 숫자를 생성for i in count(10, 2): if i > 20: break print(i, end=' ') # 출력: 10 12 14 16 18 20# zip_longest는 가장 긴 이터러블이 끝날 때까지 묶음을 만들고, 부족한 곳은 fillvalue로 채워줌list_a = [1, 2,..
안녕하세요! 지난 글들에서 우리는 파이썬 itertools의 다양한 기능—range, enumerate, zip, map, filter, chain, takewhile, dropwhile, accumulate, groupby—를 C++에서도 나름 “파이썬스럽게” 구현하거나 표현하는 방법을 두루 살펴봤습니다. 이번에는 itertools의 대표적인 조합론적(iteration over combinations) 함수들인 product, permutations, combinations를 살펴보려고 합니다. 이 함수들은 파이썬에서 꽤 자주 쓰입니다. 예를 들어 product([1,2],[3,4])는 (1,3), (1,4), (2,3), (2,4)를 만들어내고, permutations([1,2,3], 2)는 (1,2..