standard conversion sequence
standard conversion sequence
여러 종류의 standard conversion
를 4 단계로 분류해서 standard conversion sequence
라고 한다. standard conversion sequence
의 각 단계마다 최대 하나의 standard conversion
이 변환 연산에 참여할 수 있다. 따라서 최소 0개에서 최대 4개의 standard conversion
이 연산에 참여할 수 있다.
class type에 대한 변환 연산은 1차 standard conversion sequence
→ user-defined conversion
→ 2차 standard conversion sequence
순서로 변환 연산을 진행하는데, 이를 implicit conversion sequence라
고 부르는데, standard conversion sequence
용어와 다소 헷갈릴 수 있다.
스펙 문서의 conversion이 standard conversion sequence에 포함되는 것은 아니다. 예를 들어, temporary materialization conversion는 standard conversion sequence에 포함된 변환이 아니다.
최대 하나 적용:
[[lvalue transformation conversion category]]- lvalue-to-rvalue conversion
- array-to-pointer conversion
- function-to-pointer conversion
최대 하나 적용:
[[promotion conversion category]]- integral promotions
- floating-point promotion
[[conversion conversion category]]
- integral conversions
- floating-point conversions
- floating-integral conversions
- pointer conversions
- pointer-to-member conversions
- boolean conversions
최대 하나 적용:
[[qualification adjustment conversion category]]- function pointer conversion
최대 하나 적용:
[[qualification adjustment conversion category]]- qualification conversion
standard conversion sequence를 수행하는 경우
- 피연산자에 대해, 연산자의 요구 타입으로
standard conversion sequence
를 수행한다. - if condition에 대해, bool 타입으로
standard conversion sequence
를 수행한다. - switch expression에서 대해, integral 타입으로
standard conversion sequence
를 수행한다. - initializer에 대해(return expression, function call argument, initialization expression 포함), 초기화 할려는 entity 타입으로
standard conversion sequence
를 수행한다.
standard conversion sequence를 활용하는 사례
C++ 스펙에서는 standard conversion sequence를 수행하는 과정에서, 특정 standard conversion를 금하거나, 특정 조건을 만족하는 standard conversion를 허용한다.
예를 들어, reference-compatible(cv1 T1, cv2 T2)
연산의 아규먼트 T1, T2 타입에 대해, T1 expression의 pointer prvalue category에서 T2 expression의 pointer type으로 변환을 명시한 standard conversion만을 standard conversion sequence에서 허용하고 나머지 standard conversion을 금한다.
예를 들어, & operator의 피연산자는 lvalue-to-rvalue conversion를 제외한 standard conversion만을 standard conversion sequence로 허용한다.
예를 들어, class type에 대해, conversion이 필요하면, 1차 standard conversion sequence → user-defined conversion → 2차 standard conversion sequence 순서로 implicit conversion sequence를 진행한다. 이 때, 2차 standard conversion sequence는 1차 standard conversion sequence에 비해 제한된 범위에서 작용한다.
예를 들어, discarded-value expression
에서는 array-to-pointer conversion, function-to-pointer conversion를 무시하고, lvalue-to-rvalue conversion는 volatile-qualified 타입의 glvalue category
에 대해서만 적용한다.
value category, cv-qualification, data representation는 서로 독립적이다.
lvalue-to-rvalue conversion를 적용한 결과는 cv-qualification, data representation를 변경하지 않는다.
promotions conversion과 type conversion를 적용한 결과는 value category, cv-qualification를 변경하지 않는다.
qualification conversion를 적용한 결과는 value category, data representation를 변경하지 않는다.
conversion Rank 이해하기
value category, cv-qualification, data representation는 서로 독립적이다. 3 종류를 모두 변경하지 않는 변환은 identity conversion category라고 한다.
value category만 변경하는 변환 카테고리를 lvalue Transformation conversion category라고 한다.
cv-qualification만 변경하는 변환 카테고리를 qualification adjustment conversion category라고 한다.
data representation만 변경하는 변환 카테고리를 promotion conversion category 또는 conversion conversion category라고 한다.
data representation를 변경하지 않는 rank를 exact match rank라고 한다. 즉, identity conversion category, lvalue transformation conversion category, qualification adjustment conversion category가 exact match rank로 분류된다.
promotion conversion으로 data representation를 변경하는 rank는 promotion rank로 분류된다.
promotion가 아닌 conversion으로 data representation를 변경하는 rank는 conversion rank로 분류된다.
컴파일러가 선호한 변환 순위는 data representation를 변경하지 않는 exact match rank의 우선 순위가 높고, 다음으로 promotion rank, 다음으로 conversion rank순이다.
T t = E;
E 타입에서 T로의 암묵적 변환 구문이다.
예를 들어, switch 구문의 expression에 암묵적 변환을 요구한다.
struct A {
explicit operator int() const { return 10; }
};
int main(int argc, char* argv[]) {
A a{};
int v = a; // ERROR
switch (a) { // ERROR
case 10:
break;
}
return 0;
}
예를 들어, function call의 argument에 암묵적 변환을 요구한다.
struct A {
explicit operator bool() const { return true; }
};
struct B {
B(int) {}
};
void f1(int) {}
void f2(B) {}
int main(int argc, char* argv[]) {
A a{};
f1(a); // ERROR
f2(a); // ERROR
return 0;
}
예를 들어, return 구문의 expression에 암묵적 변환을 요구한다.
struct A {
explicit operator bool() const { return true; }
};
int f() {
A a{};
return a; // ERROR
}
T t(E);
E 타입에서 T로의 명시적 변환 구문이다.
예를 들어, if 구문의 condition에 명시적 변환을 요구한다.
#include <print>
struct A {
explicit operator bool() const { return true; }
};
int main(int argc, char* argv[]) {
A a{};
bool v(a); // OK
if (a) { // OK
std::print("{}", v);
}
return 0;
}
[출력 결과]
true