콘텐츠로 이동

C++20 std::source_location 완전 가이드

C++20 이전에는 파일명, 줄 번호, 함수명을 얻으려면 __FILE__, __LINE__, __func__ 매크로를 사용해야 했습니다. 이 매크로들은 타입 안전하지 않고 템플릿과 조합하기 어렵습니다. C++20의 std::source_location은 이를 표준화된 방법으로 해결합니다.


#include <source_location>
#include <iostream>
void logLocation() {
auto loc = std::source_location::current();
std::cout << "파일: " << loc.file_name() << "\n";
std::cout << "함수: " << loc.function_name() << "\n";
std::cout << "줄 번호: " << loc.line() << "\n";
std::cout << "열 번호: " << loc.column() << "\n";
}
멤버 함수반환값
file_name()소스 파일 경로 (const char*)
function_name()함수 이름 (시그니처 포함)
line()줄 번호 (uint_least32_t)
column()열 번호 (uint_least32_t)

// 기존 매크로 방식
#define LOG(msg) std::cout << "[" << __FILE__ << ":" << __LINE__ << "] " << msg << "\n"
// std::source_location 방식
void log(std::string_view msg,
std::source_location loc = std::source_location::current()) {
std::cout << "[" << loc.file_name() << ":"
<< loc.line() << "] " << msg << "\n";
}
// 호출 측 코드가 위치 정보를 자동으로 전달
log("초기화 완료"); // [main.cpp:42] 초기화 완료

std::source_location::current()기본 인수로 사용하면 호출 지점의 위치가 자동으로 캡처됩니다.


#include <source_location>
#include <string_view>
#include <iostream>
#include <format>
enum class LogLevel { Debug, Info, Warn, Error };
class Logger {
public:
static void log(
LogLevel level,
std::string_view message,
std::source_location loc = std::source_location::current())
{
const char* levelStr = [level] {
switch (level) {
case LogLevel::Debug: return "DEBUG";
case LogLevel::Info: return "INFO ";
case LogLevel::Warn: return "WARN ";
case LogLevel::Error: return "ERROR";
}
return "?????";
}();
std::cout << std::format("[{}] {}:{} ({}) — {}\n",
levelStr,
loc.file_name(),
loc.line(),
loc.function_name(),
message);
}
};
void initialize() {
Logger::log(LogLevel::Info, "시스템 초기화 시작");
// [INFO ] main.cpp:55 (void initialize()) — 시스템 초기화 시작
}

void assert_impl(bool condition, std::string_view message,
std::source_location loc = std::source_location::current()) {
if (!condition) {
std::cerr << "Assertion failed: " << message << "\n"
<< " at " << loc.file_name()
<< ":" << loc.line()
<< " in " << loc.function_name() << "\n";
std::abort();
}
}
#define ASSERT(cond, msg) assert_impl((cond), (msg))
void processData(int value) {
ASSERT(value > 0, "값은 양수여야 합니다");
// Assertion failed: 값은 양수여야 합니다
// at process.cpp:42 in void processData(int)
}

기존 __FILE__, __LINE__ 매크로는 템플릿 함수에서 항상 호출 지점이 아닌 정의 지점을 가리킵니다. source_location은 기본 인수를 통해 올바른 호출 지점을 캡처합니다.

template<typename T>
void logValue(const T& value,
std::source_location loc = std::source_location::current()) {
std::cout << loc.file_name() << ":" << loc.line()
<< " value=" << value << "\n";
}
// 각각 다른 파일:줄 출력
logValue(42);
logValue(std::string("hello"));
logValue(3.14);

class CallTracer {
std::source_location loc_;
std::string funcName_;
public:
explicit CallTracer(
std::source_location loc = std::source_location::current())
: loc_(loc), funcName_(loc.function_name())
{
std::cout << "[ENTER] " << funcName_ << "\n";
}
~CallTracer() {
std::cout << "[EXIT] " << funcName_ << "\n";
}
};
void complexFunction() {
CallTracer tracer; // 함수 진입/종료 자동 로그
// 작업 수행
}
// [ENTER] void complexFunction()
// [EXIT] void complexFunction()

class AppException : public std::exception {
std::string message_;
std::source_location location_;
public:
explicit AppException(
std::string message,
std::source_location loc = std::source_location::current())
: message_(std::move(message)), location_(loc) {}
const char* what() const noexcept override {
return message_.c_str();
}
const std::source_location& where() const noexcept {
return location_;
}
};
void riskyOperation() {
throw AppException("데이터베이스 연결 실패");
}
int main() {
try {
riskyOperation();
} catch (const AppException& e) {
std::cerr << "오류: " << e.what() << "\n"
<< "위치: " << e.where().file_name()
<< ":" << e.where().line() << "\n";
}
}

특성__FILE__ / __LINE__std::source_location
타입const char* / int타입 안전 구조체
템플릿 호환X (정의 지점 캡처)O (호출 지점 캡처)
컴파일러 확장비표준 매크로C++20 표준
함수명__func__ (비표준)function_name()
열 번호비표준column()

// 주의: 함수 객체나 람다에서의 function_name()은 구현체마다 다름
auto lambda = [] {
auto loc = std::source_location::current();
std::cout << loc.function_name() << "\n";
// GCC: "main()::<lambda>"
// MSVC: "__cdecl main::<lambda_...>"
};
// 주의: current()는 반드시 기본 인수 위치에서 사용해야 함
// 함수 본문 내부에서 호출하면 함수 내부 위치가 캡처됨
void badUsage(std::source_location loc) { // 기본 인수 없음
// loc는 항상 badUsage 호출 측의 정보가 아님
}

  • std::source_location::current()를 기본 인수로 사용하면 호출 지점 정보 자동 캡처
  • __FILE__, __LINE__, __func__ 매크로를 타입 안전하게 대체
  • 로깅, 어서션, 예외, 트레이싱에 활용
  • 템플릿 함수에서도 올바른 호출 지점을 캡처