2017-10-17 16 views
30

bug 80985 itibaren, bu örneği düşünün: Bütün uyarılara ile bu derleniyorTaşıma gcc en noexcept tipi uyarısı

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

void func() noexcept { } 

int main() 
{ 
    call(func); 
} 

etkin, sizin gibi, verimleri:

$ 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) 
     ^~~~ 

tam olarak yapacağım ne yapmak Bu uyarı ile? Düzeltme nedir?

+1

Eğer 'çağrı' projenize tamamen dahilse, önemli değil. Sadece iki farklı çeviri ünitesinin kullanıldığı durumlarda, C++ 17 ile bir tane derlenmediği ve birinin olmadığı durumlarda önemlidir. O zaman bile, 'çağırma' bir şablon işlevi olduğu için, muhtemelen son çalıştırılabilirlikte fazladan bir tanıma sahip olmaktan çok büyük bir etkiye sahip olmayacaktır. –

+2

@DanielH Yukarıda Barry için konuşmak istediğimden değil, ama -wError ile bir proje derliyorsanız, o zaman "zararsız uyarı", programın doğru olmasına rağmen, derlenmemesine neden olacaktır. Bu önemli. – markt1964

+1

@ markt1964 Sadece yazımda '-Wall' kullanılır. '-Werror ile derlerseniz veya derleyici hatalarından kaçınmaya çalışırsanız (ki bu iyi bir fikirdir), o zaman evet, bir sorunla karşılaşırsınız. Belki de, en iyi, koşullara bağlı olarak -Wo-noexcept-type' ekleyerek ele alınabilir. –

cevap

18

Uyarı mesajı hakkında yapabileceğiniz birkaç şey var.

-Wno-noexcept-type ile devre dışı bırakın. Birçok projede uyarı mesajı yararsızdır çünkü sonuçta ortaya çıkan nesnenin GCC'nin C++ 17 ad mangantasyonunu kullanmasını bekleyen başka bir nesne ile bağlantılı olma ihtimali yoktur. Farklı -std= ayarlarıyla derleme yapmıyorsanız ve saldırganlık işlevinin ortak arabiriminin parçası olduğu statik veya paylaşılan bir kitaplık oluşturmuyorsanız, uyarı iletisi güvenli bir şekilde devre dışı bırakılabilir.

Tüm kodunuzu -std=c++17 ile derleyin. Fonksiyon yeni mandallı ismi kullanacağından uyarı mesajı sönecektir.

static işlevini kullanın. Fonksiyon başka bir nesne dosyası tarafından fonksiyon için farklı bir managülasyon kullanılarak referans alınamayacağından, uyarı mesajı görüntülenmeyecektir. İşlev tanımlaması, onu kullanan tüm derleme birimlerine dahil edilmek zorundadır, ancak örnekte olduğu gibi şablon işlevleri için bu zaten yaygındır. Ayrıca bu üye fonksiyonları için işe yaramaz static başka bir şey demektir.

Bir işlev şablonu çağrıldığında, istisna belirtimine sahip olmayan uyumlu bir işlev işaretçi türü vermek için şablon parametresini belirtin. Örneğin call<void (*)()>(func). Bunu yapmak için oyuncuyu da kullanabilmeniz gerekir, ancak GCC 7.2.-std=c++17 kullanımı, manganlamayı değiştirmese bile 0 hala bir uyarı oluşturur.

İşlev şablon olmadığında, işlev türünde kullanılan işlev işaretçisi türleriyle noexcept kullanmayın. Bu ve son nokta, yalnızca atanmamış işlev gösterici türlerinin manevra değişikliklerini adlandırmayla sonuçlandığına ve atıcı olmayan işlev işaretleyicilerinin atanabileceğine (C++ 11) veya örtük olarak (C++ 17) atanmasına neden olur. işlev işaretçileri.

0

onlar hakkında uyarıda bulunuyorlar mesele C++ 14'de, işe yarayacak ki:

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

void func() noexcept {} 

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

ama C++ 17 olmak call beyanı değiştirmek gerekir içinde:

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

Şablon olarak call tanımladığınızdan, bunun için endişelenmeniz gerekmez. Yine de, sorunlara neden olabilir çünkü türetilen tür değişiyor, bu genellikle gerçekleşmiyor.

Örneğin, bu kod C++ 14 değil, C++ 17 derlenir:

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 arasında C++ 14, tiplerde ve bar aynıdır, fakat farklı olan C++ 17'de şablon çözünürlüğü başarısız olur. bayrak -std=c++1z ile gcc 7.2 hata iletisi şudur:

Verdiğiniz örnekte
note: template argument deduction/substitution failed: 
note: deduced conflicting types for parameter 'F' ('void (*)() noexcept' and 'void (*)()') 

, hiçbir sorun olduğunu ve C++ 14 veya C++ 17 yılında derleme bir sorun olmaz modu. Eğer kod buradaki örnekden daha karmaşıksa (örneğin, yukarıda verdiğim örneklere benzer), bazı derleyici problemleriyle karşılaşabilirsiniz. Yeni bir derleyiciniz var gibi görünüyor; -std=c++1z ile derlemeye çalışın ve uyarı veya hata olup olmadığını görün.

+0

Bu soruya cevap vermiyor. Tür sistemine 'noexcept' eklenmesinin farkındayım. – Barry

+0

Sonunda daha fazla açıklama ekledim; umarım bu konuyu açıklığa kavuşturur – SJL

3

Ross'un call<void (*)()>(func) çözümü için yanıtını kaldırıyorum. Derleyici, şablonun noexcept işlev türü için başlatılmasını istediğinizi açıkça belirtir ve kodunuzun C++ 17'de olduğu gibi C++ 17'de tam olarak aynı olmasını garanti eder.

fazla alternatif:

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

void func() noexcept { } 

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

(2) noexcept olmayan ayrı bir sarıcı fonksiyonu oluşturma:

(1) (noexcept değildir) bir lambda noexcept fonksiyonu sarın. Bu daha başlangıçta yazıyor, ancak birden fazla çağrı siteniz varsa, genel yazmayı kaydedebilirsiniz. Bu, orijinal olarak GCC hatasını dosyalamam için bana gönderilen kodda what I ended up doing olduğunu.