2016-08-04 2 views
20

"noexcept 지정자 (및 연산자)"를 연구하면서 간단한 코드를 작성했습니다.C++ 17 예외 지정자 유형 시스템은 어떻게 작동합니까?

void asdf() noexcept {} 
int main() 
{ 
    auto f = asdf; 
    std::cout << std::boolalpha << noexcept(f()) << std::endl; 
} 

인쇄 false, 심지어 기능 "asdf을"noexcept 지정이다 : 그리고 나는이 코드 조각이 놀랄입니다.

왜이 신비로운 현상이 일어나고 있는지 검색하면서 C++ 17의 "예외 지정자 유형 시스템"인 P0012R1을 발견했습니다.

이 (제안 된) 제안에 따르면, C++ 17; noexcept은 함수 유형의 일부이므로 위의 코드는 true입니까? this 질문의 한 라인에서

그리고 하나 더, :

noexcept 지정은 무시 보인다
std::function<void() noexcept> f 

C++ (14) 또는 (11) 이 C++ (17)이 코드가 작동 의도 한 바와 같이?

+0

g ++'-std = C++ 1z'없이'noexcept (f())'에'true'를 반환합니다 (그러나 clang은'false'를 반환합니다). – Holt

+0

재미를 위해서'auto f = asdf;'를'void (* f)() noexcept = asdf;'로 변경하십시오. 이제 GCC는 clang이'true'를 인쇄하는 동안'false'를 인쇄합니다. – hvd

+0

@Holt 정보를 제공해 주셔서 감사합니다. MSVC ('false '를 반환)를 사용하고 있습니다. 그들 중 무엇이 다른가? 그것은 g ++ 또는 C++ 14 또는 이전 표준의 버그가'noexcept' 유형 시스템에 대해 아무 것도 지정하지 않았습니까? – Gear

답변

11

이 (제안 된) 제안에 따르면, C++ 17; noexcept는 함수 유형의 일부이므로 위 코드는 인쇄 할 것입니다 true?

예. asdf에 적용되는 함수에 대한 포인터 변환이 noexcept 속성을 보존하기 때문에

f의 유형은 void(*)() noexcept으로 추론됩니다. noexcept 함수 포인터에 대한 호출은 하위 표현식 중 하나가 않는 한 확실히 예외를 throw 할 수 없습니다.

정확한 표현은 [expr.unary.noexcept]/3[expect.spec]/13을 참조하십시오. C++ 17 초안의 후반 단락에서 새로운 문구는 OP에서 링크 된 P0012R1에서 비롯된 것입니다.

noexcept 연산자의 결과는 식 ([except.spec])의 전위 예외의 집합이 비어있는 경우 true이고, 그렇지 false.

...

  • e 함수 호출 ([expr.call])이면

    : 그 후위 표현가 (아마도 괄호) ID 표현 경우
    • 캐스트 표현식id- 표현 인 구성원 멤버 액세스 ([expr.prim.id]), 클래스 멤버 액세스 ([expr.ref]) 또는 멤버 포인터 작업 ([expr.mptr.oper]) , S은 포함 된 id 표현식 (해당하는 경우 과부하 해결 후)에 의해 선택된 엔티티의 예외 사양에있는 유형 집합입니다. ...

그래서 f()의 잠재적 인 예외의 세트는 fnoexcept 선언되어 있기 때문에 비어 f의 예외 사양의 종류의 설정과 동일합니다.

의 두 번째 질문으로 이동하자

noexcept 지정은 C++ (14) 또는 (11)는 C++ (17)이 코드가 작동 의도 한 바와 같이를 무시 보인다?

귀하의 질문은 다음과 같을 것입니다 : std::function<void() noexcept> 예외를 throw 할 수있는 기능을 거부하겠습니까?

나는 그것이 이라고 분명히 말할 것입니다. 표준의 현재 표현에서 std::function<void() noexcept>은 실제로 정의되어 있지 않으며 단지 std::function<double(float) const> is not defined입니다. noexcept이 함수 유형의 일부로 간주되지 않았기 때문에 이것은 물론 C++ 14에서는 문제가되지 않았습니다.

std::function<void() noexcept>은 C++ 17에서 간단히 깨지십니까? 그건 나에게 불확실하다. 행동이 "있어야"하는 것을 추측하기 위해 현재의 표현을 살펴 보겠습니다.

표준은, 인수 형 ArgTypes... 및 반환형 R은 "좌변 호출 가능"으로 std::function<R(ArgTypes..)>의 생성자에 인자를 요구하는 means :

호출 가능한 유형 ([func.def]) F 평가되지 않은 피연산자 (절 [expr])로 간주되는 표현식 INVOKE(declval<F&>(), declval<ArgTypes>()..., R)이 올바른 형식 ([func.require]) 인 경우 인수 유형 ArgTypes 및 반환 유형 R에 대해 LVWLvalue-Callable입니다.

아마도 함수 유형이 noexcept 인 경우 noexcept(INVOKE(...))도 true 여야한다는 추가 요구 사항이 있어야합니다. 그럼에도 불구하고,이 문구는 현재 초안에 존재하지 않는다.

std::function을 통해 "noexcept"을 전파하는 방법 개방 문제 :

는 P0012R1에서하는 의견이있다.

제 생각에이 추가 요구 사항이 부과 된 경우 std::function을 어떻게 구현할 수 있는지는 명확하지 않습니다. 다행히도 다른 사람이 더 자세한 정보를 제공 할 수 있습니다.

+1

분명히 우리는'std :: function_moveonly'와'std :: function_noexceptonly'와'std :: function_moveonly_noexceptonly'가 필요합니다. 하지만'std :: function_mutablecall'은 어떨까요? 이것은 지저분해질 수 있습니다. – Yakk