अगर कॉन्स्ट्रेप - क्यों खारिज कर दिया गया बयान पूरी तरह से जांचा गया है?


14

मैं GCC 10 में c ++ 20 कॉन्स्टेवल के साथ गड़बड़ कर रहा था और यह कोड लिखा था

#include <optional>
#include <tuple>
#include <iostream>

template <std::size_t N, typename Predicate, typename Tuple>
consteval std::optional<std::size_t> find_if_impl(Predicate&& pred,
                                                  Tuple&& t) noexcept {
  constexpr std::size_t I = std::tuple_size_v<std::decay_t<decltype(t)>> - N;

  if constexpr (N == 0u) {
    return std::nullopt;
  } else {
    return pred(std::get<I>(t))
               ? std::make_optional(I)
               : find_if_impl<N - 1u>(std::forward<decltype(pred)>(pred),
                                      std::forward<decltype(t)>(t));
  }
}

template <typename Predicate, typename Tuple>
consteval std::optional<std::size_t> find_if(Predicate&& pred,
                                             Tuple&& t) noexcept {
  return find_if_impl<std::tuple_size_v<std::decay_t<decltype(t)>>>(
      std::forward<decltype(pred)>(pred), std::forward<decltype(t)>(t));
}

constexpr auto is_integral = [](auto&& x) noexcept {
    return std::is_integral_v<std::decay_t<decltype(x)>>;
};


int main() {
    auto t0 = std::make_tuple(9, 1.f, 2.f);
    constexpr auto i = find_if(is_integral, t0);
    if constexpr(i.has_value()) {
        std::cout << std::get<i.value()>(t0) << std::endl;
    }
}

जिसे एसटीएल के एल्गोरिथ्म की तरह काम करने के लिए माना जाता है, लेकिन ट्यूपल्स पर और एक पुनरावृत्तिकर्ता को वापस करने के बजाय, यह एक कंपाइल समय पर आधारित एक वैकल्पिक इंडेक्स को लौटाता है। अब यह कोड ठीक ठीक संकलित करता है और यह प्रिंट करता है

9

लेकिन अगर टपल में एक ऐसा तत्व नहीं है जो एक अभिन्न प्रकार है, तो प्रोग्राम संकलित नहीं करता है, क्योंकि i.value () अभी भी एक खाली वैकल्पिक पर कहा जाता है। अब ऐसा क्यों है?



@AndyG जो इसे ठीक नहीं करता है, हालांकि यह करता है? x)
यामाहारी

जवाबों:


11

अगर काम करता है तो यह सिर्फ विवशता है । अगर हम [stmt.if] / 2 की जांच करते हैं

यदि अगर बयान फॉर्म का है अगर कॉन्स्टैक्स, स्थिति का मूल्य प्रकार के बूल का एक प्रासंगिक रूप से परिवर्तित स्थिर अभिव्यक्ति होगा; इस फॉर्म को स्टेटमेंट कहा जाता है। यदि परिवर्तित स्थिति का मान गलत है, तो पहला सबस्टेशन एक डिस्क्राइब्ड स्टेटमेंट है, अन्यथा दूसरा सबस्टेशन, यदि मौजूद है, तो एक खारिज किया गया स्टेटमेंट है। एक संलग्न टेम्प्लेटेड इकाई ([temp.pre]) की तात्कालिकता के दौरान, यदि स्थिति उसके तात्कालिकता के बाद मूल्य-निर्भर नहीं है, तो खारिज किए गए सबस्टेशन (यदि कोई हो) को तत्काल नहीं किया जाता है। [...]

जोर मेरा

इसलिए हम देख सकते हैं कि हम केवल त्याग की गई अभिव्यक्ति का मूल्यांकन नहीं करते हैं यदि हम एक टेम्पलेट में हैं और यदि स्थिति मूल्य-निर्भर है। mainएक फ़ंक्शन टेम्प्लेट नहीं है, इसलिए यदि विवरण के शरीर को अभी भी शुद्धता के लिए संकलक द्वारा जांचा जाता है।

Cppreference यह भी कहते हैं कि यदि उनके पास कब्ज़ के बारे में खंड में है:

यदि एक गतिरोधी इकाई के अंदर बयान दिखाई देता है, और अगर तात्कालिकता के बाद स्थिति मूल्य-निर्भर नहीं है, तो संलग्न विवरण तत्काल नहीं दिया जाता है, जब संलग्न टेम्पलेट को त्वरित किया जाता है।

template<typename T, typename ... Rest>
void g(T&& p, Rest&& ...rs) {
    // ... handle p
    if constexpr (sizeof...(rs) > 0)
        g(rs...); // never instantiated with an empty argument list.
}

एक टेम्पलेट के बाहर, एक खारिज किए गए बयान को पूरी तरह से जांचा जाता है। अगर कॉन्स्ट्रेप #if प्रीप्रोसेसिंग निर्देश के लिए एक विकल्प नहीं है:

void f() {
    if constexpr(false) {
        int i = 0;
        int *p = i; // Error even though in discarded statement
    }
}

क्या आप इसके लिए तर्क जानते हैं? ऐसा लगता है कि अगर कॉन्स्टैक्स के लिए यह एक अच्छा फिट होगा। इसलिए भी समाधान किसी भी तरह से एक टेम्पलेट में लपेटकर किया जाएगा?
यमहरि

@Yamahari क्योंकि C ++ टेम्प्लेट आप जितना चाहते हैं, उससे कम और संरचित दोनों हैं। और हां, इसे एक टेम्प्लेट में लपेटें (या लिखें i.value_or(0))
बैरी

2
@ यमहारी हां, समाधान एक फ़ंक्शन टेम्पलेट में कोड डालना होगा। जहां तक ​​तर्क जाता है, मुझे नहीं पता कि क्यों। यह शायद एक अच्छा सवाल है।
नेथनऑलिवर

@ बेरी value_or (0) ठीक काम करता है लेकिन मामले के लिए जब
टुपल

@ यमहारी हां ... मेरी ओर से अच्छा सुझाव नहीं।
बैरी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.