삶의 공유
C++ ADL (Argument Dependent Lookup) 완벽 정리 본문
📘 C++ ADL (Argument Dependent Lookup) 완벽 정리
C++을 배우다 보면 draw_pixel(pt); 처럼 namespace를 생략했는데도 함수가 잘 호출되는 걸 볼 수 있습니다.
“아니, Graphics::draw_pixel()이 아닌데 왜 되는 거지?”
그 이유가 바로 ADL(Argument Dependent Lookup), 즉 인자 종속 이름 탐색(또는 Koenig Lookup) 입니다.
이 문법은 C++에서 함수 검색 방식에 매우 중요한 역할을 합니다.
🧩 1. ADL이란?
함수 호출 시, 인자(argument)의 타입이 속한 네임스페이스(namespace)를 자동으로 탐색에 포함시키는 규칙
→ Koenig Lookup이라고도 불립니다.
즉, 함수의 이름만 보고 찾는 게 아니라
“이 함수의 인자가 어디 소속인지”를 기준으로 추가적인 탐색 범위가 자동으로 확장됩니다.
🎯 2. 예제로 이해하는 ADL
namespace Graphics {
class Point {};
void draw_pixel(const Point& p1) {
std::println("Draw pixel in Graphics namespace");
}
void set_color(int c) {}
}
int main() {
Graphics::Point pt;
// 명시적 호출
Graphics::draw_pixel(pt);
// ADL 덕분에 이렇게도 가능!
draw_pixel(pt);
}
🔍 실행 결과
Draw pixel in Graphics namespace
Draw pixel in Graphics namespace
💡 설명
- pt는 Graphics::Point 타입입니다.
- 컴파일러는 draw_pixel(pt)를 찾을 때,
- 현재 스코프(전역 등)에서 draw_pixel을 찾고,
- pt가 속한 네임스페이스(Graphics)도 탐색 대상에 포함합니다.
- 결국 Graphics::draw_pixel()을 찾아 호출합니다.
즉, draw_pixel(pt) → Graphics::draw_pixel(pt) 로 자동 연결됩니다.
이 동작이 바로 ADL 입니다.
🧠 3. ADL이 만들어진 이유
ADL이 없다면, 다음과 같은 불편한 코드가 되어버립니다.
std::string s1, s2;
s1 + s2; // ✅ 실제로는 잘 동작함 (ADL 덕분)
하지만 ADL이 없다면 이렇게 써야 합니다:
std::operator+(s1, s2); // ❌ 너무 장황하고 비직관적
즉, ADL은 연산자 오버로딩을 자연스럽게 사용할 수 있게 해주는 핵심 문법입니다.
표준 라이브러리(std::string, std::vector, std::swap 등)에서도 ADL이 광범위하게 사용됩니다.
🧩 4. ADL이 동작하는 예: std::string 연산자
namespace std {
class string {
// 실제 구현은 훨씬 복잡하지만 예시를 위해 단순화
};
string operator+(const string& s1, const string& s2) {
return s1; // (단순 예시용)
}
}
int main() {
std::string s1, s2;
s1 + s2; // ✅ 가능 — ADL이 std namespace를 탐색에 포함
}
💡 설명
- s1과 s2는 std::string 타입입니다.
- 컴파일러가 operator+를 찾을 때
→ std 네임스페이스를 자동으로 탐색 범위에 추가 - 그 결과 std::operator+ 를 찾아 호출하게 됩니다.
ADL이 없다면 s1 + s2 는 컴파일 에러가 납니다.
⚙️ 5. std::swap 예시로 보는 ADL의 한계
#include <algorithm>
#include <string>
int main() {
int n1 = 10;
int n2 = 20;
std::string s1 = "AAA";
std::string s2 = "BBB";
std::swap(n1, n2); // ✅ 명시적으로 std::swap 호출
std::swap(s1, s2); // ✅ std::string은 std::swap이 있음
swap(s1, s2); // ✅ ADL 작동 — string은 std 네임스페이스 타입
swap(n1, n2); // ❌ 에러 — int는 std에 속하지 않음
}
💬 해설
| std::string | std | std::swap 탐색 성공 | ✅ OK |
| int | 전역 타입 | 없음 (네임스페이스 X) | ❌ 컴파일 에러 |
👉 기본 타입(int, double 등) 은 네임스페이스에 속하지 않기 때문에
ADL로 탐색할 공간이 없습니다.
따라서 swap(n1, n2)는 실패하지만, swap(s1, s2)는 성공합니다.
⚙️ 6. 실무에서의 권장 사용법
C++ 표준 함수(std::swap, std::sort, std::begin 등)는 가독성을 위해 std::를 붙이는 것이 권장됩니다.
즉,
std::swap(x, y); // ✅ 명시적 호출 권장
swap(x, y); // ✅ ADL 작동은 하지만 가독성 ↓
using std::swap;
swap(a, b); // ✅ 사용자 정의 타입이면 ADL로, 아니면 std::swap 호출
이 패턴은 표준 라이브러리에서도 자주 사용됩니다.
🔎 7. ADL의 핵심 동작 요약
| 이름 탐색 방식 | 인자의 타입이 속한 네임스페이스를 자동 탐색 |
| 적용 대상 | 일반 함수, 연산자 함수 |
| 효과 | namespace:: 생략 가능 |
| 대표 예시 | std::string의 operator+, std::swap |
| 주의사항 | 기본 타입(int 등)은 ADL이 적용되지 않음 |
| 권장사항 | std::swap 등은 가독성을 위해 std::를 붙이는 습관 |
📌 핵심 요약
- ADL (Argument Dependent Lookup) = “함수 인자의 네임스페이스를 자동 탐색하는 규칙”
- 이유: 연산자 오버로딩과 네임스페이스 분리를 자연스럽게 연결하기 위해
- 효과: draw_pixel(pt) → Graphics::draw_pixel(pt) 자동 인식
- 주의: int, double 같은 기본형은 ADL 대상이 아님
- 실무 팁: 표준 함수는 std::를 명시적으로 쓰는 게 더 안전하고 명확함
'Programing언어 > C++' 카테고리의 다른 글
| C++ 상속에서의 복사 생성자와 대입 연산자 완전 정리 (0) | 2025.10.18 |
|---|---|
| C++에서 Shallow Copy와 Deep Copy 완벽 정리 — 복사의 진짜 차이를 이해하자 (0) | 2025.10.16 |
| C++ 함수 객체(Function Object) 완전 정리 (0) | 2025.09.29 |
| C++ 스마트 포인터(Smart Pointer) 완전 정리 (0) | 2025.09.29 |
| [C++] Null Ptr (널포인터) 기본 다지기 (1) | 2024.02.17 |