연산자 대체 표현
연산자 대체 표현 (Alternative operator representations)
C++ 소스 코드는 ISO 646:1983 고정 문자 집합(invariant character set)을 포함하는 비(非) ASCII 7비트 문자 집합 어디서든 쓸 수 있어요. 그런데 몇몇 C++ 연산자와 구두점은 ISO 646 코드셋 밖의 문자({, }, [, ], #, \, ^, |, ~)가 필요해요. 이 기호 중 일부(혹은 전부)가 없는 문자 인코딩(예: 독일 DIN 66003)을 쓸 수 있도록, C++는 ISO 646 호환 문자로 이루어진 다음과 같은 대체(token)를 정의해요.
본문
대체 토큰 (Alternative tokens)
비(非) ISO646 문자를 쓰는 여러 연산자와 토큰에는 대체 철자가 있어요. 언어의 모든 측면에서 각 대체 토큰은 철자만 다를 뿐 기본 토큰(primary token)과 정확히 똑같이 동작해요. (문자열화 연산자 #가 철자를 드러나게 할 수는 있어요.) 두 글자짜리 대체 토큰은 가끔 digraph라고 불러요. %:%:는 네 글자지만 이것도 digraph로 간주해요.
| 기본 | 대체 |
|---|---|
&& |
and |
&= |
and_eq |
& |
bitand |
| |
bitor |
~ |
compl |
! |
not |
!= |
not_eq |
|| |
or |
|= |
or_eq |
^ |
xor |
^= |
xor_eq |
{ |
<% |
} |
%> |
[ |
<: |
] |
:> |
# |
%: |
## |
%:%: |
트라이그래프 (Trigraphs, C++17에서 제거)
다음 세 문자 그룹(트라이그래프)은 주석과 문자열 리터럴이 인식되기 전에 파싱되고, 트라이그래프가 나타날 때마다 해당 기본 문자로 치환돼요:
| 기본 | 트라이그래프 |
|---|---|
{ |
??< |
} |
??> |
[ |
??( |
] |
??) |
# |
??= |
\ |
??/ |
^ |
??' |
| |
??! |
~ |
??- |
트라이그래프는 아주 일찍 처리되기 때문에 주의할 점이 있어요. // Will the next line be executed?????/ 같은 주석은 실제로 다음 줄을 주석 처리하게 되고, "Enter date ??/??/??" 같은 문자열 리터럴은 "Enter date \\??"로 파싱돼요.
참고 (Notes)
문자 &와 !는 ISO-646 하에서도 고정 문자이지만, 이 문자를 쓰는 토큰에도 더 제약적인 역사적 문자 집합을 수용하기 위해 어쨌든 대체가 제공돼요.
동등성 연산자 ==에는 (eq 같은) 대체 철자가 없어요. 왜냐하면 문자 =는 지원되는 모든 문자 집합에 존재했기 때문이에요.
C와의 호환성 (Compatibility with C)
C 프로그래밍 언어에서는 같은 단어들이 <iso646.h> 헤더 파일에 매크로로 정의돼 있어요. C++에서는 이것들이 언어에 내장되어 있기 때문에 C++ 버전의 <iso646.h>와 <ciso646>는 아무것도 정의하지 않아요. 다만 단어가 아닌 digraph(예: <%)는 핵심 언어의 일부라서 어떤 헤더도 포함하지 않고 쓸 수 있어요. (그렇지 않으면 #가 없는 어떤 문자 집합에서든 쓸 수 없게 되거든요.)
키워드
and, and_eq, bitand, bitor, compl, not, not_eq, or, or_eq, xor, xor_eq
예제
다음 예제는 여러 대체 토큰을 사용하는 모습을 보여줘요.
%:include <iostream>
struct X
<%
compl X() <%%> // destructor
X() <%%>
X(const X bitand) = delete; // copy constructor
// X(X and) = delete; // move constructor
bool operator not_eq(const X bitand other)
<%
return this not_eq bitand other;
%>
%>;
int main(int argc, char* argv<::>)
<%
// lambda with reference-capture:
auto greet = <:bitand:>(const char* name)
<%
std::cout << "Hello " << name
<< " from " << argv<:0:> << '\n';
%>;
if (argc > 1 and argv<:1:> not_eq nullptr)
greet(argv<:1:>);
else
greet("Anon");
%>
가능한 출력:
Hello Anon from ./a.out
이 예제를 보면 %:include는 #include를, <%·%>는 {·}를, <:·:>는 [·]를, bitand는 &를, not_eq는 !=를, and는 &&를, compl은 ~를 각각 대체한 것임을 알 수 있어요. 일반적인 코드에서 이렇게 쓸 일은 드물지만, 문자가 부족한 환경에서의 호환성을 위해 존재해요.
표준 문서 (References)
- C++23 표준 (ISO/IEC 14882:2024) — 5.5 Alternative tokens [lex.digraph]
- C++20 표준 (ISO/IEC 14882:2020) — 5.5 Alternative tokens [lex.digraph]
- C++17 표준 (ISO/IEC 14882:2017) — 5.5 Alternative tokens [lex.digraph]
- C++14 표준 (ISO/IEC 14882:2014) — 2.4 Trigraph sequences [lex.trigraph], 2.6 Alternative tokens [lex.digraph]
- C++11 표준 (ISO/IEC 14882:2011) — 2.4 Trigraph sequences [lex.trigraph], 2.6 Alternative tokens [lex.digraph]
- C++03 표준 (ISO/IEC 14882:2003) — 2.3 Trigraph sequences [lex.trigraph], 2.5 Alternative tokens [lex.digraph]
- C++98 표준 (ISO/IEC 14882:1998) — 2.3 Trigraph sequences [lex.trigraph], 2.5 Alternative tokens [lex.digraph]
더 알아보기 (Learn more)
- 연산자 우선순위와 결합성 — 다양한 연산자가 어떤 우선순위로 평가되는지 정리한 페이지예요.
- C 문서 — Alternative operators and tokens.