2017-10-17 9 views
30

bug 80985에서,이 예제를 고려하십시오 : 모든 경고와 함께이 컴파일취급 GCC의 noexcept 형 경고

template <class Func> 
void call(Func f) 
{ 
    f(); 
} 

void func() noexcept { } 

int main() 
{ 
    call(func); 
} 

활성화, 당신처럼, 수율 :

$ g++ -std=c++14 -Wall foo.cxx 
foo.cxx:2:6: warning: mangled name for ‘void call(Func) [with Func = void (*)() noexcept]’ will change in C++17 because the exception specification is part of a function type [-Wnoexcept-type] 
void call(Func f) 
     ^~~~ 

정확히 내가 생각하고 어떻게 할 이 경고와 함께? 수정 프로그램은 무엇입니까?

+1

'call'이 프로젝트의 내부적 인 경우라면 상관 없습니다. 두 개의 다른 번역 단위가 그것을 사용하는 경우에만 중요합니다. 하나는 C++ 17로 컴파일되었고 하나는 그렇지 않았습니다. 그렇더라도'call'은 템플릿 함수이기 때문에 최종 실행 파일에 여분의 정의를 갖는 것 이외에 큰 영향을 미치지 않을 것입니다. –

+2

@DanielH 위의 Barry에 대해 말하고자하는 것이 아니라, -wError를 사용하여 프로젝트를 컴파일하는 경우 해당 "무해한 경고"로 인해 프로그램이 올바르게 컴파일되지 않을 수 있습니다. 그게 중요해. – markt1964

+1

@ markt1964 게시물에는'-Wall' 만 사용됩니다. '-Werror'로 컴파일하거나 컴파일러 에러 (좋은 생각이다)를 피하려고한다면, 그렇다. 문제가 생길 것이다. 상황에 따라'-Wno-noexcept-type'을 추가함으로써 가장 잘 처리 될 수있는 것. –

답변

18

경고 메시지에 대해 할 수있는 몇 가지 사항이 있습니다.

-Wno-noexcept-type으로 사용 중지합니다. 많은 프로젝트에서 경고 메시지는 도움이되지 않습니다. 왜냐하면 결과 객체가 GCC의 C++ 이름 맹 글링을 사용할 것으로 기대하는 다른 객체와 링크 될 가능성이 없기 때문입니다. 다른 -std= 설정으로 컴파일하지 않고 문제가되는 기능이 공용 인터페이스의 일부인 정적 또는 공유 라이브러리를 작성하지 않으면 경고 메시지를 안전하게 비활성화 할 수 있습니다.

모든 코드를 -std=c++17으로 컴파일하십시오. 함수가 새로운 맹 글링 된 이름을 사용하기 때문에 경고 메시지가 사라집니다.

static으로 설정하십시오. 함수에 대해 다른 맹 글링을 사용하여 다른 오브젝트 파일이 함수를 더 이상 참조 할 수 없으므로 경고 메시지가 표시되지 않습니다. 함수 정의는 그것을 사용하는 모든 컴파일 유닛에 포함되어야하지만 예제에서와 같이 템플릿 함수의 경우 이것은 일반적입니다. 또한 이것은 멤버 함수에 대해 작동하지 않습니다. static은 다른 것을 의미합니다.

함수 템플릿을 호출 할 때 템플릿 매개 변수를 명시 적으로 지정하면 예외 사양이없는 호환 가능한 함수 포인터 유형을 제공합니다. 예 : call<void (*)()>(func). 또한 이것을 사용하여 캐스트를 사용할 수 있어야하지만 GCC 7.2.0은 여전히 ​​-std=c++17을 사용하여 맹 글링을 변경하지 않더라도 경고를 생성합니다.

함수가 템플릿이 아닌 경우 함수 유형에 사용 된 모든 함수 포인터 유형과 함께 noexcept을 사용하지 마십시오. 이 점과 마지막 점은 비 던진 함수 포인터 유형 만 명명 변경 사항을 초래하고 비 던진 함수 포인터를 할당 (C++ 11)하거나 암시 적으로 변환 (C++ 17)하여 던져 버릴 수 있다는 사실에 의존합니다 함수 포인터.

0

그들에 대해 경고하고있다 문제는 C++ 14이 작동하는 것입니다 :

void call(void (*f)()) 
{ 
    f(); 
} 

void func() noexcept {} 

int main(int argc, char* argv[]) 
{ 
    call(&func); 
    return 0; 
} 

을하지만, C++ 17, 당신이되고 call의 선언을 변경해야의 :

void call(void (*f)() noexcept) 
{ 
    f(); 
} 

call을 템플릿으로 정의 했으므로 걱정할 필요가 없습니다. 추측 된 유형이 변경되기 때문에 문제가 발생할 수 있지만 일반적으로 발생하지는 않습니다.

예를 들어,이 코드는 C++ 14 아니라 C++ 17 컴파일 :

void foo() noexcept {} 
void bar()   {} 

template <typename F> 
void call(bool b, F f1, F f2) 
{ 
    if (b) 
     f1(); 
    else 
     f2(); 
} 

void foobar(bool b) 
{ 
    call(b, &foo, &bar); 
} 

foo의 C++ 14 종류 및 bar이 동일한, 그러나 이들은 다른 C++ 17에서는 템플릿 해상도가 실패합니다. 플래그 -std=c++1z와 GCC 7.2의 오류 메시지는 다음과 같습니다

당신이 준 예에서
note: template argument deduction/substitution failed: 
note: deduced conflicting types for parameter 'F' ('void (*)() noexcept' and 'void (*)()') 

, 거기에 아무 문제가 없다 당신이 C++ (14) 또는 C++ 17에서 컴파일 문제가되지 않습니다 방법. 코드가 여기 예보다 복잡하다면 (예를 들어 위에서 설명한 예제와 비슷 함) 일부 컴파일러 문제가 발생할 수 있습니다. 최근 컴파일러가있는 것 같습니다. -std=c++1z으로 컴파일을 시도하고 경고 또는 오류가 있는지 확인하십시오.

+0

이것은 질문에 대답하지 않습니다. 저는 타입 시스템에'noexcept '를 추가 한 것을 알고 있습니다. – Barry

+0

끝에 더 많은 설명을 추가했습니다. 문제를 분명히 밝히는 바램 – SJL

3

나는 call<void (*)()>(func) 솔루션에 대한 로스의 답변을 upvoting했습니다. 명시 적으로 컴파일러에게 템플릿이 noexcept이 아닌 함수 유형에 대해 인스턴스화되도록하고 C++ 17에서와 똑같이 코드가 작동하도록합니다.

추가 대안은 :

template <class Func> 
void call(Func f) 
{ 
    f(); 
} 

void func() noexcept { } 

int main() 
{ 
    call([]() { func(); }); 
} 

(2) noexcept 않고 ​​별도 래퍼 함수 생성 :

(1) (noexcept 아니다) 람다의 noexcept 함수 감싸. 이것은 처음에는 더 많은 타이핑이지만, 여러 호출 사이트를 가지고 있다면 타이핑 전체를 줄일 수 있습니다. 이것은 원래 GCC 버그를 제출하도록 요청한 코드에 what I ended up doing입니다.