2017-10-17 282 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++ 17名稱修飾的對象鏈接。如果您沒有使用不同的-std=設置進行編譯,而且您沒有構建靜態或共享庫,其中違規功能是其公共接口的一部分,則可以安全地禁用警告消息。

-std=c++17編譯您的所有代碼。警告消息將消失,因爲該函數將使用新的名稱。

使功能static。由於函數不能再被另一個對象文件引用,因爲函數使用了不同的函數,所以不會顯示警告消息。函數定義必須包含在所有使用它的編譯單元中,但對於你的例子中的模板函數,這是很常見的。此外,這不會成員功能static意味着別的東西。

在調用函數模板時,請指定模板參數,明確指定一個沒有異常規範的兼容函數指針類型。例如call<void (*)()>(func)。你也應該可以使用cast來做到這一點,但GCC 7.2。即使使用-std=c++17也不會改變加固,0仍然會生成警告。

當函數不是模板時,請不要將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

我對Ross提出的call<void (*)()>(func)解決方案的回答很滿意。它明確告訴編譯器,您希望模板實例化爲非noexcept函數類型,並確保您的代碼在C++ 17中的操作與在C++ 14中的操作完全相同。

更多替代方案是:

(1)包裹在一個lambda的noexcept功能(這是不noexcept):

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

void func() noexcept { } 

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

(2)無noexcept創建一個單獨的包裝函數。這是最初的打字,但如果你有多個電話網站,它可以節省打字的整體。這是代碼中的what I ended up doing,最初提示我提交GCC錯誤。