C ++에서 throw가 표현식이면 그 유형은 무엇입니까?


115

나는 reddit에 대한 나의 짧은 시도 중 하나에서 이것을 선택했습니다.

http://www.smallshire.org.uk/sufficientlysmall/2009/07/31/in-c-throw-is-an-expression/

기본적으로 저자는 C ++에서 다음과 같이 지적합니다.

throw "error"

표현입니다. 이것은 실제로 본문과 문법 모두에서 C ++ 표준에서 상당히 명확하게 설명되어 있습니다. 그러나 (적어도 나에게) 명확하지 않은 것은 표현의 유형이 무엇입니까? " void"을 추측 했지만 g ++ 4.4.0 및 Comeau로 약간의 실험을 통해이 코드를 생성했습니다.

    void f() {
    }

    struct S {};

    int main() {
        int x = 1;
        const char * p1 = x == 1 ? "foo" : throw S();  // 1
        const char * p2 = x == 1 ? "foo" : f();        // 2
    }

컴파일러는 // 1에 문제가 없었지만 조건 연산자의 유형이 다르기 때문에 // 2에 barfed했습니다. 따라서 throw표현 의 유형 이 공허하지 않은 것 같습니다.

그래서 그것은 무엇입니까?

답변이 있으면 표준의 인용문을 사용하여 진술을 백업하십시오.


이것은 조건 연산자가 throw 식을 처리하는 방법만큼 throw 식의 유형에 관한 것이 아니라는 것이 밝혀졌습니다. 오늘 전에는 확실히 알지 못했던 것입니다. 답장 한 모든 사람에게 감사하지만 특히 David Thornley에게 감사드립니다.

c++  throw 

10
+1 멋진 질문입니다. 그리고 그것을 테스트하는 영리한 방법.
Jeremy Powell

1
이 링크는 컴파일러에 의해 유형이 필요한 것으로 결정된다는 것을 상당히 명확하게하는 것 같습니다.
Draemon 2009-07-31

링크 된 기사는 내가 본 이후로 업데이트되었다고 생각하며 실제로 그럴 것이라고 확신합니다. 그러나 표준에서는 찾을 수 없습니다.

A 그리고 아마 아닐 수도 있습니다-double d = throw "foo"; g + = 오류입니다 (comau로 테스트하지 않음)

+1 답이 궁금합니다.
AraK

답변:


96

표준에 따르면 5.16 단락 2 첫 번째 지점은 "두 번째 또는 세 번째 피연산자 (둘다는 아님)는 throw-expression (15.1)입니다. 결과는 다른 유형이고 rvalue입니다." 따라서 조건부 연산자는 throw-expression이 어떤 유형인지 상관하지 않고 다른 유형 만 사용합니다.

사실, 15.1, 단락 1은 명시 적으로 "throw-expression은 void 유형입니다."라고 말합니다.


9
좋아요-승자가 있다고 생각합니다.

throw-expression은 할당 식입니다. 따라서 대부분의 연산자에 대한 인수로서 구문 오류입니다. 분명히 괄호 안에 숨길 수 있지만 무시되지 않으면 (예를 들어 내장 operator의 첫 번째 인수) 유형 오류입니다.
AProgrammer

4
정말 놀랍게도 그들이이 사건을 생각하고 합리적인 일을 만들었다는 것입니다.
Omnifarious

31

"throw-expression은 void 유형입니다."

ISO14882 섹션 15


그렇다면 g ++와 Comeau는 모두 // 1 케이스에 오류를주지 않는다는 점에서 기각됩니까?

2
@Neil, C ++ / 5.16 / 2에 따르면 조건부 연산자의 두 번째 및 세 번째 피연산자가 유형이 될 수 있기 때문에 실제로는 아닙니다void
mloskot

13

[expr.cond.2] (조건부 연산자 ?:)에서 :

두 번째 또는 세 번째 피연산자에 void 유형 (가능하면 cv-qualifined)이 있으면 lvalue-rvalue, 배열-포인터 및 함수-포인터 표준 변환이 두 번째 및 세 번째 피연산자에서 수행됩니다. 다음 중 하나가 유지됩니다.

— 두 번째 또는 세 번째 피연산자 (둘다는 아님)가 throw-expression입니다. 결과는 다른 유형이며 rvalue입니다.

— 두 번째 및 세 번째 피연산자 모두 void 유형입니다. 결과는 void 유형이고 rvalue입니다. [참고 : 여기에는 두 피연산자가 throw-expression 인 경우가 포함됩니다. — 끝 참고]

따라서 //1첫 번째 경우에,을 (를 //2) 사용하면 "다음 중 하나가 유지 될 것입니다"를 위반하는 것입니다.


3

타입 프린터 가 당신을 위해 그것을 뱉어 낼 수 있습니다 .

template<typename T>
struct PrintType;

int main()
{
    PrintType<decltype(throw "error")> a; 
}

기본적으로에 대한 구현이 없으면 PrintType컴파일 오류 보고서에 다음과 같은 내용이 표시됩니다.

정의되지 않은 템플릿의 암시 적 인스턴스화 PrintType<void>

우리가 실제로 확인할 수 있도록 throw표현 유형입니다 void(그리고 예, 다른 답변에서 언급 한 표준 견적이는 구현 고유의 결과 아닌지 확인 - GCC는 가치있는 정보를 인쇄 힘든 시간을 가지고 있지만)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.