std::in_place_t
개념
std::in_place_t
는 C++17 표준 라이브러리에서 도입된 tag type이다.
생성자 호출 시 내부 객체를 직접 생성하겠다는 의도를 전달하기 위해 사용되는 특별한 타입이다.
std::optional
, std::variant
, std::any
같은 컨테이너 클래스에서
내부 값을 초기화할 생성자 인자를 전달하고자 할 때 사용된다.
이 타입의 목적은 **“이 생성자 호출은 내부 객체의 생성자 인자로 전달된다”**는 것을 컴파일러와 사람 모두에게 명확히 하기 위함이다.
tag type이란?
tag type은 특별한 의미를 전달하기 위해 만들어진 빈 struct나 class 타입을 의미한다.
값을 전달하기 위해서가 아니라 **의도를 전달하기 위한 타입 기반 신호(signal)**로 쓰인다. 주로 함수나 생성자 오버로딩에서 어떤 버전을 호출할지를 구분짓는 역할을 한다.
예시:
struct my_tag_t {};
constexpr my_tag_t my_tag{};
이렇게 tag type을 만들고, 함수 호출 시 my_tag
를 인자로 넘겨서 어떤 오버로드 버전을 호출할지를 구분할 수 있다.
std::in_place_t 정의
std::in_place_t
는 표준 라이브러리에서 다음과 같이 정의되어 있다.
namespace std {
struct in_place_t { explicit in_place_t() = default; };
inline constexpr in_place_t in_place{};
}
std::in_place
는 std::in_place_t
타입의 상수 객체로, 생성자나 함수에 인자로 넘겨 사용한다.
구현 예시는 다음 링크에서 확인 가능하다: https://en.cppreference.com/w/cpp/utility/in_place
활용 예시
std::optional에서 사용
#include <optional>
#include <string>
#include <iostream>
int main() {
std::optional<std::string> opt1("hello"); // 문자열 리터럴로 생성
std::optional<std::string> opt2(std::in_place, 5, 'x'); // string(5, 'x') 생성자 호출
std::cout << *opt1 << std::endl; // 출력: hello
std::cout << *opt2 << std::endl; // 출력: xxxxx
}
첫 번째는 "hello"
라는 문자열을 미리 만들어 optional
에 저장하는 방식이고,
두 번째는 optional
내부의 std::string
객체를 string(5, ‘x’) 생성자로 직접 초기화하는 방식이다.
std::in_place
가 없으면 std::optional<std::string> opt(5, 'x');
와 같이 모호성 에러가 발생할 수 있다.
std::variant에서 사용
#include <variant>
#include <string>
#include <iostream>
int main() {
std::variant<int, std::string> v1(std::in_place_index<1>, 5, 'x');
std::variant<int, std::string> v2(std::in_place_type<std::string>, 5, 'x');
std::cout << std::get<1>(v1) << std::endl; // 출력: xxxxx
std::cout << std::get<1>(v2) << std::endl; // 출력: xxxxx
}
std::in_place_index<1>
은 인덱스 1(std::string
) 타입을 선택하여 생성자를 호출한다.
std::in_place_type<std::string>
는 타입으로 직접 선택한다.
이 방식으로 어떤 타입의 값을 생성할지와 생성자 인자를 명시적으로 지정할 수 있다.
장점
- 생성자 오버로딩에서 의도를 명확히 표현할 수 있다.
- 컴파일 타임에 타입 안전성을 확보할 수 있다.
- 모호성(ambiguity)을 방지할 수 있다.