C ++ टेम्पलेट टेम्पलेट तर्क प्रकार कटौती


10

मेरे पास कोड है जो स्ट्रिंग्स के कंटेनर के ऊपर जाकर एक पैटर्न के मैचों को ढूंढता है और प्रिंट करता है। टेम्पू में फंक्शन फू में प्रिंटिंग की जाती है

कोड

#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
#include <string>
#include <tuple>
#include <utility>

template<typename Iterator, template<typename> class Container>
void foo(Iterator first, Container<std::pair<Iterator, Iterator>> const &findings)
{
    for (auto const &finding : findings)
    {
        std::cout << "pos = " << std::distance(first, finding.first) << " ";
        std::copy(finding.first, finding.second, std::ostream_iterator<char>(std::cout));
        std::cout << '\n';
    }
}

int main()
{
    std::vector<std::string> strs = { "hello, world", "world my world", "world, it is me" };
    std::string const pattern = "world";
    for (auto const &str : strs)
    {
        std::vector<std::pair<std::string::const_iterator, std::string::const_iterator>> findings;
        for (std::string::const_iterator match_start = str.cbegin(), match_end;
             match_start != str.cend();
             match_start = match_end)
        {
            match_start = std::search(match_start, str.cend(), pattern.cbegin(), pattern.cend());
            if (match_start != match_end)
                findings.push_back({match_start, match_start + pattern.size()});
        }
        foo(str.cbegin(), findings);
    }

    return 0;
}

संकलित करते समय मुझे एक त्रुटि मिली है कि पुनरावृत्तियों की असंगतता के कारण प्रकार कटौती विफल हो गई है, उनके प्रकार विविध होते हैं।

जीसीसी संकलन त्रुटि:

prog.cpp:35:9: error: no matching function for call to 'foo'
        foo(str.cbegin(), findings);
        ^~~
prog.cpp:10:6: note: candidate template ignored: substitution failure [with Iterator = __gnu_cxx::__normal_iterator<const char *, std::__cxx11::basic_string<char> >]: template template argument has different template parameters than its corresponding template template parameter
void foo(Iterator first, Container<std::pair<Iterator, Iterator>> const &findings)
     ^
1 error generated.

क्लैंग का उत्पादन:

main.cpp:34:9: error: no matching function for call to 'foo'
        foo(str.cbegin(), findings);
        ^~~
main.cpp:9:6: note: candidate template ignored: substitution failure [with Iterator = std::__1::__wrap_iter<const char *>]: template template argument has different template parameters than its corresponding template template parameter
void foo(Iterator first, Container<std::pair<Iterator, Iterator>> const &findings)

मैं क्या नहीं पकड़ रहा हूँ? क्या खाका टेम्पलेट प्रकारों का मेरा उपयोग गलत है और मानक दृष्टिकोण से दुरुपयोग दिखाई देता है? न तो जी ++ - 9.2 के साथ listdc ++ 11 है और न ही बजना ++ साथ libc ++ इस संकलन करने में सक्षम हैं।


1
यह ध्वज के साथ -std=c++17और Clang पर GCC पर काम करता है -std=c++17-frelaxed-template-template-args। अन्यथा ऐसा लगता है कि आपको आवंटनकर्ता के लिए एक और टेम्पलेट पैरामीटर की आवश्यकता है।
होलीब्लैककैट

@HolyBackCat, वास्तव में, धन्यवाद
dannftk

जवाबों:


10

आपका कोड C ++ 17 के बाद से ठीक काम करना चाहिए। (यह gcc10 के साथ संकलित है ।)

टेम्प्लेट टेम्प्लेट तर्क std::vectorमें दो टेम्प्लेट पैरामीटर होते हैं (दूसरे में डिफ़ॉल्ट तर्क होता है std::allocator<T>), लेकिन टेम्प्लेट टेम्प्लेट पैरामीटर Containerमें केवल एक होता है। सी ++ 17 (के बाद से राष्ट्रमंडल खेलों 150 ), डिफ़ॉल्ट टेम्पलेट तर्क के लिए अनुमति दी जाती है टेम्पलेट टेम्पलेट तर्क कम टेम्पलेट मानकों के साथ टेम्पलेट टेम्पलेट पैरामीटर मिलान करने के लिए।

template<class T> class A { /* ... */ };
template<class T, class U = T> class B { /* ... */ };

template<template<class> class P> class X { /* ... */ };

X<A> xa; // OK
X<B> xb; // OK in C++17 after CWG 150
         // Error earlier: not an exact match

C ++ 17 से पहले, आप टेम्पलेट टेम्पलेट पैरामीटर Container, उदाहरण के लिए डिफ़ॉल्ट तर्क के साथ 2 टेम्पलेट पैरामीटर को परिभाषित कर सकते हैं

template<typename Iterator, template<typename T, typename Alloc=std::allocator<T>> class Container>
void foo(Iterator first, Container<std::pair<Iterator, Iterator>> const &findings)

या पैरामीटर पैक लागू करें ।

template<typename Iterator, template<typename...> class Container>
void foo(Iterator first, Container<std::pair<Iterator, Iterator>> const &findings)

1

C ++ के कुछ संस्करणों में, Containerमेल नहीं खा सकता है std::vector, क्योंकि std::vectorवास्तव में ए नहीं है template <typename> class। यह वह जगह है template <typename, typename> classजहां दूसरा पैरामीटर (आवंटन प्रकार) में एक डिफ़ॉल्ट टेम्पलेट तर्क है।

यद्यपि यह एक और टेम्पलेट पैरामीटर जोड़ने के typename Allocलिए कार्य Container<std::pair<Iterator, Iterator>, Alloc>कर सकता है, फ़ंक्शन पैरामीटर बनाता है , जो अन्य कंटेनर प्रकारों के लिए एक समस्या हो सकती है।

लेकिन चूंकि आपका फ़ंक्शन वास्तव में टेम्पलेट टेम्प्लेट पैरामीटर का उपयोग नहीं करता है Container, इसलिए इस तरह के जटिल टेम्पलेट तर्क कटौती की आवश्यकता नहीं है, टेम्पलेट टेम्पलेट तर्क को कम करने के सभी गोच और सीमाओं के साथ:

template<typename Iterator, class Container>
void foo(Iterator first, Container const &findings);

यह भी Iteratorतीन अलग-अलग स्थानों में सटीक एक ही प्रकार के रूप में कटौती करने की आवश्यकता नहीं है । मतलब यह एक पारित करने के लिए मान्य होगा X::iteratorके रूप में firstऔर एक कंटेनर युक्त X::const_iteratorया ठीक इसके विपरीत है, और टेम्पलेट तर्क कटौती अभी भी सफल हो सकते हैं।

एक छोटी सी खामी यह है कि यदि कोई अन्य टेम्पलेट SFINAE तकनीकों का उपयोग करके यह निर्धारित करने का प्रयास करता है कि क्या एक हस्ताक्षर fooवैध है, तो यह घोषणा लगभग किसी भी चीज़ से मेल खाएगी, जैसे foo(1.0, 2)। यह अक्सर विशिष्ट उद्देश्य के लिए महत्वपूर्ण नहीं होता है, लेकिन कम से कम सामान्य प्रयोजन के कार्यों के लिए अधिक प्रतिबंधक (या "एसएफआईएनएई-अनुकूल") होना अच्छा है। हम कुछ के साथ एक बुनियादी प्रतिबंध जोड़ सकते हैं:

// Require Container is container-like (including raw array or std::initializer_list)
// and its values have members first and second of the same type,
// which can be compared for equality with Iterator.
template <typename Iterator, class Container>
auto foo(Iterator first, Container const &findings)
    -> std::void_t<decltype(first == std::begin(findings)->first),
           std::enable_if_t<std::is_same_v<std::begin(findings)->first, 
                            std::begin(findings)->second>>>;

वास्तव में मैं हमेशा यह सुनिश्चित करना चाहता हूं कि मापदंडों में प्रदान किया गया कंटेनर मानों को std के रूप में बताता है :: पुनरावृत्तियों की जोड़ी जिसमें पहले पैरामीटर का प्रकार होता है, इसलिए आपके द्वारा दिए गए टेम्पलेट फ़ंक्शन का पहला सरलीकरण मेरी आवश्यकताओं को पूरा करने के लिए प्रतीत नहीं हो सकता है, इसके विपरीत यह दूसरा समाधान SFINAE के साथ करेगा। वैसे भी, बहुत बहुत धन्यवाद
dannftk
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.