সি ++ টেম্পলেট টেম্পলেট আর্গুমেন্ট প্রকারের ছাড়


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সহ জিসিসিতে এবং সংঘর্ষে কাজ করে -std=c++17-frelaxed-template-template-args। অন্যথায় মনে হচ্ছে বরাদ্দকারীর জন্য আপনার আর একটি টেম্পলেট প্যারামিটার প্রয়োজন।
হলি ব্ল্যাককিট

@ হোলিব্ল্যাকগ্যাট, সত্যই আপনাকে ধন্যবাদ
ড্যানফটক

উত্তর:


10

আপনার কোডটি সি ++ 17 এর পরে কাজ করে work (এটি gcc10 দিয়ে সংকলন করে ))

টেমপ্লেট টেমপ্লেট আর্গুমেন্টে std::vectorদুটি টেম্পলেট প্যারামিটার রয়েছে (২ য়টির ডিফল্ট আর্গুমেন্ট রয়েছে std::allocator<T>), তবে টেমপ্লেট টেমপ্লেট প্যারামিটারগুলির মধ্যে Containerএকটি রয়েছে। সি ++ 17 ( সিডাব্লুজি 150 ), কম টেম্পলেট প্যারামিটারগুলির সাথে টেমপ্লেট টেমপ্লেট প্যারামিটারের সাথে টেমপ্লেট টেমপ্লেট আর্গুমেন্টের সাথে মেলানোর জন্য ডিফল্ট টেম্পলেট আর্গুমেন্টগুলিকে অনুমোদিত are

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

সি ++ 17 আগে, আপনি টেমপ্লেট টেমপ্লেট প্যারামিটার জন্য ডিফল্ট আর্গুমেন্ট সহ 2nd টেমপ্লেট প্যারামিটার বর্ণনা করতে পারেন Container, যেমন

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

সি ++ এর কয়েকটি সংস্করণে, 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বা তদ্বিপরীত, এবং টেমপ্লেট যুক্তি সিদ্ধান্তগ্রহণ এখনও সফল পারে।

একটি সামান্য অসুবিধা হ'ল যদি অন্য কোনও টেমপ্লেট স্বাক্ষর fooবৈধ কিনা তা নির্ধারণের জন্য SFINAE কৌশল ব্যবহার করে , যে ঘোষণাটি প্রায় কোনও কিছুর সাথে মিলবে foo(1.0, 2)। এটি প্রায়শই নির্দিষ্ট-উদ্দেশ্যমূলক কার্যক্রমে গুরুত্বপূর্ণ নয় তবে কমপক্ষে সাধারণ উদ্দেশ্যে কাজকর্মের জন্য আরও সীমাবদ্ধ (বা "SFINAE- বান্ধব") হওয়া ভাল। আমরা এরকম কিছু দিয়ে একটি প্রাথমিক সীমাবদ্ধতা যুক্ত করতে পারি:

// 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>>>;

প্রকৃতপক্ষে আমি সর্বদা নিশ্চিত করতে চাই যে প্যারামিটারগুলিতে সরবরাহিত কনটেইনারটি মান হিসাবে স্ট্যান্ডার্ড :: প্রথম প্যারামিটারের ধরণ রয়েছে এমন পুনরাবৃত্তির জোড়া, সুতরাং আপনার দেওয়া টেম্পলেট ফাংশনটির প্রথম সরলকরণটি আমার প্রয়োজনীয়তাগুলি পূরণ করতে পারে না বলে বিপরীতে এটি আপনার দ্বিতীয় SFINAE এর সাথে সমাধান করবে। যাইহোক, আপনাকে অনেক ধন্যবাদ
ড্যান্টফটক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.