2015-04-24 5 views
6

मुझे पता है कि =default के रूप में चिह्नित एक कन्स्ट्रक्टर noexcept होने पर "कोशिश करें" होगा। हालांकि, अगर मैं इसे बाहर वर्ग को परिभाषित, यह noexcept अब और नहीं है, जैसा कि आप इस कोड से देख सकते हैं:क्लास के बाहर परिभाषित डिफ़ॉल्ट कन्स्ट्रक्टर कैसे बनाया जाए?

#include <iostream> 
#include <utility> 
#include <type_traits> 

struct Bar 
{ 
    Bar() = default; 
    Bar(Bar&&) = default; // noexcept 
}; 

struct Foo 
{ 
    Foo() = default; 
    Foo(Foo&&); 
}; 
// moving the definition outside makes it noexcept(false) 
Foo::Foo(Foo&&) = default; // not noexcept anymore 

int main() 
{ 
    Foo foo; 
    Bar bar; 
    std::cout << std::boolalpha; 
    // checks 
    std::cout << std::is_nothrow_move_constructible<Bar>::value << std::endl; 
    std::cout << std::is_nothrow_move_constructible<Foo>::value << std::endl; 
} 

मैं कैसे एक वर्ग के बाहर इस तरह के एक =default निर्माता परिभाषित कर सकते हैं और यह noexcept बनाते हैं? और कक्षा के बाहर परिभाषित किए गए ऐसे निर्माता noexcept(false) क्यों हैं? स्मार्ट पॉइंटर्स के माध्यम से PIMPL लागू करते समय यह समस्या उत्पन्न होती है।

उत्तर

2

अपने दो उदाहरण के लिए अपवाद विनिर्देश संचालन नियम §8.4.2/2 [dcl.fct.def.default]

में कवर कर रहे हैं ... एक समारोह स्पष्ट रूप से है अपनी पहली घोषणा में चूक,
— यह परोक्ष constexpr होने के लिए अगर अंतर्निहित घोषणा होगा माना जाता है,
यह परोक्ष ही अपवाद-विनिर्देश वाला माना जाता है जैसे कि वह परोक्ष घोषित कर दिया गया था (15.4), और
— ...

Bar की चाल निर्माता है noexcept(true) क्योंकि में §15.4/14 [except.spec]

एक निहित घोषित विशेष सदस्य समारोह (क्लॉज 12) में अपवाद-विनिर्देश होगा। तो f एक परोक्ष घोषित डिफ़ॉल्ट निर्माता है,, निर्माता, चाल निर्माता, नाशक कॉपी असाइनमेंट ऑपरेटर कॉपी, या असाइनमेंट ऑपरेटर ले जाते हैं, अपने निहित अपवाद-विनिर्देशप्रकार आईडीT यदि और केवल यदि T निर्दिष्ट करता है अपवाद-विनिर्देश द्वारा सीधे फ़ंक्शन के f की अंतर्निहित परिभाषा द्वारा अनुमत किए जाने की अनुमति है; f सभी अपवादों को अनुमति देगा यदि कोई भी फ़ंक्शन सीधे इनवॉर्ड्स को सभी अपवादों की अनुमति देता है, और f कोई अपवाद की अनुमति नहीं देगा यदि प्रत्येक फ़ंक्शन इसे सीधे आमंत्रित करता है तो कोई अपवाद नहीं देता है।

§8.4.2/2 में नियम जो विशेष §12 मामलों में कर रहे हैं विशेष सदस्य कार्यों है कि स्पष्ट रूप से प्रारंभिक घोषणा के बाद चूक गई, विनाशकर्ता को छोड़कर, पर लागू नहीं हैं।4/3 noexcept(true) होने तक जब तक आप इसे noexcept(false) घोषित नहीं करते हैं या डेटा सदस्यों या बेस क्लास में से किसी एक के विनाशक फेंक सकते हैं।

इस प्रकार, जब तक आप Foo(Foo&&)noexcept(true) निर्दिष्ट नहीं करते हैं, तो यह noexcept(false) माना जाता है।

कारण तुम दोनों घोषणा और बाद में स्पष्ट डिफ़ॉल्ट घोषणा करने के लिए noexcept विनिर्देश जोड़ने की जरूरत §15.4

  दो अपवाद-विशिष्टताओं में पाया जाता है हैं संगत अगर :
— दोनों गैर फेंक (नीचे देखें) कर रहे हैं, उनके रूप की परवाह किए बिना,
— ...
  एक समारोह के किसी भी घोषणा एक अपवाद-विनिर्देश कि, एक noexcept-विनिर्देश सभी अपवादों, सभी घोषणाओं, परिभाषा और किसी भी स्पष्ट विशेषज्ञता सहित अनुमति नहीं दे रहा है कि समारोह के है, तो करेगा एक संगत अपवाद-विनिर्देश है। ...

+3

विशेष रूप से, अगर यह अपनी प्रारंभिक घोषणा के बाद चूक है, सामान्यिंग एक अलग टीयू में, हो सकता है तो एक टीयू है जो सिर्फ क्लास परिभाषा में शामिल है में, संकलक जानने का कोई तरीका नहीं है कि समारोह होगा डिफॉल्ट हो। –

+0

@ टी.सी. यह सही समझ में आता है, अब मैं समझता हूं। – vsoftco

4

मैं अब महसूस किया कि मैं यह कर सकता है, यह अब तक मेरे मन को पार नहीं किया:

struct Foo 
{ 
    Foo() = default; 
    Foo(Foo&&) noexcept; 
}; 
Foo::Foo(Foo&&) noexcept = default; // now it is noexcept 

फिर भी दूसरा सवाल ऐसा क्यों है noexcept(false) डिफ़ॉल्ट रूप से है? लागू होता है।

संबंधित मुद्दे