본문 바로가기

프로그래밍 언어/C++

C++의 underlying entity과 module 관계

반응형

C++20 모듈과 관련하여 underlying entity 개념이 특히 중요해졌습니다.

Module의 Entity 문제

모듈은 전통적인 헤더 기반 시스템과 다른 방식으로 entity를 다룹니다:

1. Entity의 도달 가능성 (Reachability)
// math.cppm
export module math;

export int add(int a, int b) {
    return a + b;
}

// main.cpp
import math;
// add의 underlying entity에 접근 가능

헤더 방식에서는 textual inclusion이었지만, 모듈에서는 semantic entity reference입니다.

2. 같은 Entity의 다중 선언
// module1.cppm
export module module1;
export using IntPtr = int*;

// module2.cppm  
export module module2;
export using IntPtr = int*;

// main.cpp
import module1;
import module2;

// 두 IntPtr는 다른 entity (서로 다른 모듈에서 선언)
// 하지만 underlying entity는 같음 (int*)
// ODR 위반 없음!
3. Module Linkage와 Underlying Entity
// lib.cppm
module;
#include <vector>

export module lib;

export using Vec = std::vector<int>;

// underlying entity인 std::vector<int>는
// global module fragment에서 온 것
// 하지만 Vec라는 alias entity는 module lib에 속함
A. 타입 통일성 (Type Identity)
// moduleA.cppm
export module moduleA;
export struct Point { int x, y; };

// moduleB.cppm
export module moduleB;
import moduleA;
export using PointAlias = Point;

// main.cpp
import moduleA;
import moduleB;

Point p1;
PointAlias p2 = p1; // OK!

// PointAlias의 underlying entity = Point
// 같은 underlying entity이므로 호환됨
B. Name Lookup의 변화

전통적 헤더:

// header.h
namespace N {
    using Type = int;
}

// source.cpp
#include "header.h"
// Type의 선언이 텍스트로 복사됨

모듈:

// mod.cppm
export module mod;
namespace N {
    export using Type = int;
}

// main.cpp
import mod;
// N::Type entity를 import
// underlying entity (int)는 semantic하게 접근
C. 재선언 규칙
// utils.cppm
export module utils;

struct Internal {};  // module-internal
export using Handle = Internal*;

// main.cpp
import utils;

// Handle 사용 가능
// 하지만 Internal은 불가능 (export 안 됨)
// Handle의 underlying entity인 Internal*는
// "도달 가능"하지만 "visible"하지 않음
Underlying Entity가 해결하는 모듈 문제들
1. 중복 import 문제
// a.cppm
export module a;
export struct Data {};

// b.cppm  
export module b;
import a;
export using DataAlias = Data;

// c.cppm
export module c;
import a;
import b;

// Data와 DataAlias는 다른 entity
// 하지만 underlying entity가 같아서 충돌 없음
2. Template Instantiation
// container.cppm
export module container;
export template<typename T>
struct Box { T value; };

// moduleA.cppm
export module moduleA;
import container;
export using IntBox = Box<int>;

// moduleB.cppm
export module moduleB;  
import container;
export using IntBox = Box<int>;

// main.cpp
import moduleA;
import moduleB;

// 두 IntBox의 underlying entity는
// 동일한 template instantiation Box<int>
// 따라서 같은 타입으로 인식됨
3. Module Partition과 Entity
// math-impl.cppm (partition)
module math:impl;
struct Calculator { /*...*/ };

// math.cppm (primary module interface)
export module math;
import :impl;
export using Calc = Calculator;

// Calc는 exported entity
// underlying entity인 Calculator는 internal
// 이 구분으로 구현 은닉 가능
Reachability vs Visibility

모듈에서 underlying entity는 두 가지 상태를 가질 수 있습니다:

// lib.cppm
module lib;

struct Internal {
    void method();
};

export using Handle = Internal*;

// 다른 곳에서
import lib;

Handle h;  // OK - Handle은 visible
h->method(); // OK - Internal::method는 reachable
Internal i;  // ERROR - Internal은 visible하지 않음
  • Visible: 이름을 직접 사용 가능
  • Reachable: 정의에 접근 가능 (underlying entity를 통해)
실용적 의미

모듈 시대의 underlying entity:

  1. ABI 안정성: underlying entity가 같으면 바이너리 호환
  2. 빌드 독립성: entity reference는 텍스트가 아닌 semantic
  3. 구현 은닉: alias로 internal entity 노출 제어
  4. 타입 시스템: 모듈 경계를 넘어 타입 동일성 보장
 
// 실제 사용 예
export module graphics;

// 구현 세부사항
namespace detail {
    struct RendererImpl { /*...*/ };
}

// 공개 인터페이스
export using Renderer = detail::RendererImpl*;

// 클라이언트는 Renderer만 보지만
// underlying entity 덕분에 실제 기능 사용 가능

모듈 시스템에서 underlying entity는 논리적 entity와 물리적 entity의 분리를 가능하게 하는 핵심 메커니즘입니다.

728x90
반응형