문제

class Foo {
  public:
  explicit Foo(double item) : x(item) {}

  operator double() {return x*2.0;}

  private:
  double x;
}

double TernaryTest(Foo& item) {
  return some_condition ? item : 0;
}

Foo abc(3.05);
double test = TernaryTest(abc);

위의 예에서, 일부가 true 인 경우 테스트가 6 (6.1 대신)과 같은 이유는 무엇입니까?

아래와 같이 코드를 변경하면 값이 6.1입니다

double TernaryTest(Foo& item) {
  return some_condition ? item : 0.0; // note the change from 0 to 0.0
}

(원래 예에서) Foo :: Operator Double의 리턴 값이 int로 캐스트 된 다음 다시 두 배로 돌입되는 것 같습니다. 왜요?

도움이 되었습니까?

해결책

조건부 운영자는 양방향으로 변환을 점검합니다. 이 경우 생성자가 명시 적이기 때문에 ?: 모호하지 않습니다), 전환 Foo 에게 int 변환하는 변환 기능을 사용하여 사용됩니다. double: 전환 함수를 적용한 후 변환하는 표준 변환이 double 에게 int (잘린) 다음. 결과 ?: 당신의 경우입니다 int, 가치가 있습니다 6.

두 번째 경우, 피연산자에 유형이 있기 때문에 double, 그러한 후행 전환은 없습니다 int 따라서 결과 유형이 이루어집니다 ?: 유형이 있습니다 double 예상 값으로.

"불필요한"변환을 이해하려면 당신과 같은 표현을 이해해야합니다. ?: "Context-Free"평가 : IT의 값과 유형을 결정할 때 컴파일러는 그것이 A의 오페라라고 생각하지 않습니다. return 반환하는 함수의 경우 a double.


편집 : 생성자 인 경우 어떻게됩니까? 절대적인? 그만큼 ?: 당신은 변환 할 수 있기 때문에 표현은 모호 할 것입니다. int 유형의 rvalue에 Foo (생성자 사용) 및 a Foo 유형의 rvalue에 int (변환 함수 사용). 표준은 말합니다

이 프로세스를 사용하면 제 2 피연산자가 세 번째 피연산자와 일치하도록 변환 될 수 있는지 여부와 제 3의 피연산자가 두 번째 피연산자와 일치하도록 변환 될 수 있는지 여부가 결정됩니다. 둘 다 변환 될 수 있거나 하나를 변환 할 수 있지만 변환이 모호한 경우 프로그램은 잘못 형성됩니다.


당신의 방법을 설명하는 단락 Foo 변환됩니다 int:

5.16/3 ~에 대한 condition ? E1 : E2:

그렇지 않으면, 두 번째 및 세 번째 피연산자가 다른 유형을 가지고 있고 (CV-qualified) 클래스 유형을 갖는 경우 각 피연산자를 다른 피연산자 유형으로 변환하려고 시도합니다. [...] E1이 E1을 일치하는 E2로 변환 될 수 있습니다.

4.3 "암시 적으로 변환 된"정보 :

표현식 e는 선언에 대해서만 유형 T로 암시 적으로 변환 될 수 있습니다. T t = e; 일부 발명 된 임시 변수 t의 경우 잘 형성되어 있습니다.

8.5/14 사본 초기화 정보 ( T t = e; )

소스 유형이 (CV-qualified) 클래스 유형 인 경우 변환 기능이 고려됩니다. 적용 가능한 변환 함수는 열거되어 있으며 (13.3.1.5), 가장 좋은 것은 과부하 해상도 (13.3)를 통해 선택됩니다. 선택된 사용자 정의 변환은 초기화 표현식을 초기화되는 객체로 변환하도록 호출됩니다. 변환을 수행 할 수 없거나 모호한 경우 초기화는 잘못 형성됩니다.

13.3.1.5 전환 기능 후보에 대해

S와 기본 클래스의 변환 기능이 고려됩니다. S 내에 숨겨져 있지 않은 것과 수율 유형 T 또는 표준 변환 시퀀스 (13.3.3.1.1)를 통해 T 형으로 변환 할 수있는 유형은 후보 함수입니다.

다른 팁

이것은 표준 5.16 절에서 긍정적으로 혼란스러운 세부 사항으로 다루어집니다. 중요한 부분은 단락 3에 있습니다. "E2가 LValue : E1을 일치하는 E2로 변환 될 수 있습니다. 참조는 E1에 직접 바인딩해야합니다 (8.5.3). "

표현에서, 유일한 lvalue는입니다 item, 질문은 0 (int)을 암시 적으로 타입으로 변환 할 수 있는지 여부입니다. Foo. 이 경우 다른 유형의 암시 적 변환은 Foo, 유일하게 사용 가능한 변환 기능이 표시되므로 explicit. 그러므로 그것은 작동하지 않으며, 우리는 "e2가 rvalue이거나 위의 변환이 완료 될 수없는 경우"(둘 다 클래스 유형이있는 경우 부품을 건너 뛰기) "를 따릅니다 (예 : E1 또는 E2 인 경우. 비 클래스 유형이 있거나 둘 다 클래스 유형이 있지만 기본 클래스는 동일하지 않거나 하나는 다른 클래스의 기본 클래스가 아닌 경우 E1이 E1을 일치시킬 수 있도록 E1을 일치시킬 수 있습니다. E2가 rvalue로 변환 된 경우 (또는 E2가 RValue 인 경우)가있는 유형). "

따라서 0은 0이 유형의 rvalue임을 알 수 있습니다. int. 우리는 변환 할 수 있습니다 Foo, 우리는 암시 적으로 변환 할 수 있기 때문에 a Foo a double 그리고 그 후 int. 그 다음에:

"이 프로세스를 사용하면 두 번째 피연산자가 세 번째 피연산자와 일치하도록 변환 될 수 있는지 여부와 제 3의 피연산자가 두 번째 피연산자와 일치하도록 변환 될 수 있는지 여부가 결정됩니다. 둘 다 변환 할 수 있으면 OOR One을 변환 할 수 있지만 변환은 변환됩니다. 모호한, 프로그램은 변환 할 수 없다면, 오페라는 변환되지 않고 아래에 설명 된대로 추가 점검이 수행됩니다. 정확히 하나의 변환이 가능하면 전환이 선택된 피연산자에 적용되고 변환 된 피연산자가 사용됩니다. 이 섹션의 나머지 부분에 대한 원래 피연산자 대신. "

우리는 변환 할 수 있기 때문에 Foo an int, 우리는 그것을 변환합니다 Foo an int 나머지 결정의 경우. 우리는 이제 두 가지를 얻었습니다 ints는 발현 유형으로, 적어도 하나는 rvalue입니다.

5 장과 6 항을 계속 사용할 수는 있지만 표현에 유형이 있다는 것이 분명하다고 생각합니다. int.

테이크 아웃은 다음과 같습니다.

  1. 컴파일러는 표준에 따라 작동합니다.

  2. 조건부 표현식의 유형에 대한 규칙은 너무 복잡하여 쉽게 배울 수 없습니다. 언젠가 실수를 저지르기 때문에 봉투를 밀지 마십시오. (게다가, 이것은 컴파일러가 표준을 정확하게 구현하지 못할 수있는 장소입니다.)

  3. 두 번째 및 세 번째 표현식이 동일한 유형이되도록 유형을 지정하십시오. 어쨌든 원하는 유형이 아닌 표현을 피하십시오.

3 원 발현의 유형은 컴파일 시간에 결정됩니다. 런타임에 어떤 _condition이 무엇인지는 중요하지 않습니다.

질문은 다음과 같은 것 같아요 : 왜 컴파일러가 첫 번째 예에서 두 배 대신 int를 선택합니까?

Ternary Operator는 인수에서 유형을 추측합니다. 항목을 int로 변환 할 수는 없지만 항목을 두 배로 변환하여 int로 변환 할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top