मैंने हाल ही में एक Reddit चर्चा का पालन किया है जो कंपाइलरों में std::visit
अनुकूलन की एक अच्छी तुलना की ओर ले जाता है । मैंने निम्नलिखित पर ध्यान दिया: https://godbolt.org/z/D2Q5ED
GCC9 और Clang9 दोनों (मुझे लगता है कि वे समान stdlib साझा करते हैं) सभी प्रकार की कुछ शर्तों को पूरा करने पर एक वैधता अपवाद की जाँच और फेंकने के लिए कोड उत्पन्न नहीं करते हैं। यह बेहतर कोडजेन की ओर जाता है, इसलिए मैंने MSVC STL के साथ एक मुद्दा उठाया और इस कोड के साथ प्रस्तुत किया गया:
template <class T>
struct valueless_hack {
struct tag {};
operator T() const { throw tag{}; }
};
template<class First, class... Rest>
void make_valueless(std::variant<First, Rest...>& v) {
try { v.emplace<0>(valueless_hack<First>()); }
catch(typename valueless_hack<First>::tag const&) {}
}
दावा किया गया था कि यह किसी भी संस्करण बेकार बना देता है, और पढ़ने के दस्तावेज यह होना चाहिए:
सबसे पहले, वर्तमान में निहित मूल्य (यदि कोई हो) को नष्ट कर देता है। फिर निहित मूल्य को प्रत्यक्ष-आरंभ करता है जैसे
T_I
कि तर्कों के साथ प्रकार के मूल्य का निर्माणstd::forward<Args>(args)....
यदि एक अपवाद फेंक दिया जाता है, तो*this
valueless_by_exception बन सकता है।
मुझे समझ में नहीं आ रहा है: इसे "मई" के रूप में क्यों कहा गया है? यदि पूरे ऑपरेशन को फेंकता है तो क्या पुरानी अवस्था में रहना कानूनी है? क्योंकि ऐसा जीसीसी करता है:
// For suitably-small, trivially copyable types we can create temporaries
// on the stack and then memcpy them into place.
template<typename _Tp>
struct _Never_valueless_alt
: __and_<bool_constant<sizeof(_Tp) <= 256>, is_trivially_copyable<_Tp>>
{ };
और बाद में यह (सशर्त रूप से) कुछ ऐसा करता है:
T tmp = forward(args...);
reset();
construct(tmp);
// Or
variant tmp(inplace_index<I>, forward(args...));
*this = move(tmp);
इसलिए मूल रूप से यह एक अस्थायी बनाता है, और यदि वह प्रतियां सफल हो जाती है / उसे वास्तविक स्थान पर ले जाती है।
IMO यह "पहले का उल्लंघन है, जो कि वर्तमान में निहित मूल्य को नष्ट करता है" जैसा कि इसने कहा है। जैसा कि मैंने मानक पढ़ा है, तब v.emplace(...)
वेरिएंट में करंट वैल्यू हमेशा नष्ट हो जाने के बाद और नया टाइप या तो सेट टाइप या वैल्युलेस होता है।
मुझे लगता है कि हालत is_trivially_copyable
उन सभी प्रकारों को शामिल करती है जिनमें एक अवलोकन योग्य विध्वंसक है। तो यह भी इस प्रकार हो सकता है: "जैसा कि अगर वैरिएंट को पुराने मूल्य के साथ पुनर्निवेशित किया जाता है" या तो। लेकिन वेरिएंट की स्थिति एक अवलोकन प्रभाव है। तो क्या मानक वास्तव में अनुमति देता है, जो emplace
वर्तमान मूल्य को नहीं बदलता है?
मानक उद्धरण के जवाब में संपादित करें:
फिर निहित मूल्य को इनिशियलाइज़ करता है जैसे कि डायरेक्ट-नॉन-लिस्ट-इनिशियलाइज़ेशन टाइप ऑफ़ द टाईल्स विथ दलील
std::forward<Args>(args)...
।
क्या T tmp {std::forward<Args>(args)...}; this->value = std::move(tmp);
वास्तव में उपरोक्त के एक वैध कार्यान्वयन के रूप में गिना जाता है? क्या इसका अर्थ "जैसे कि" है?
might/may
क्योंकि मानक यह नहीं बताता है कि विकल्प क्या है।