টেমপ্লেট শ্রেণীর উত্পন্ন করার জন্য লুপের জন্য কনস্ট কনটেবল কীভাবে থাকতে হয়?


15

আমার মত একটি কোড আছে

template <size_t N>
class A
{
    template <size_t N>
    someFunctions() {};
};

এখন আমি ক্লাসের উদাহরণ তৈরি করতে চাই এবং এর মধ্যে বিভিন্ন ফাংশনগুলিকে একটি লুপের জন্য অনেকগুলি মানের সেট হিসাবে কল করতে চাই

// in main()

int main()
{
    for (int i = 1; i <= 100; i++)
    {
        const int N = i;  // dont know how to do this
        A<N> a;
        a.functionCalls();
    }
}

এই কিভাবে করবেন? এটি করার জন্য কোনও পদ্ধতির প্রত্যাশা।


একটি টেমপ্লেট প্যারামিটার হিসাবে ব্যবহার করা Nকরা প্রয়োজন constexprযা যদি এটি একটি লুপ পরিবর্তনশীল যে ক্ষেত্রে হয়
CoryKramer

আপনি পারবেন না, সত্যিই কি টেম্পলেট হওয়ার দরকার আছে?
অ্যালান বার্টলস

হ্যাঁ কিছু কারণে ক্লাস এ এর ​​টেম্পলেট হওয়ার প্রয়োজন রয়েছে এবং এটি কোনও কিছুর একটি মডেল তাই এটি একটি টেম্পলেট শ্রেণি হতে হবে
নচিয়াপ্পান ভেঙ্কটেশ

উত্তর:


11

এর জন্য কিছু বলা দরকার template forযা প্রত্যাশিত ফর্ম সম্প্রসারণ বিবৃতি গ্রহণ করবে, যা লুপের মতো দেখতে এমন একটি বিষয় তবে বাস্তবে একাধিকবার ইনস্ট্যান্সিয়েটেড একটি ফাংশনটিতে একটি টেম্প্লেটেড ব্লক।

অবশ্যই, একটি workaround আছে। আমরা জেনেরিক ল্যাম্বডাসকে অপব্যবহার করতে পারি কিছু প্রকারের স্থানীয় টেম্পলেটড ব্লক ঘোষণা করতে এবং এটি স্বয়ংক্রিয়ভাবে ইনস্ট্যান্ট করতে:

template <typename T, T... S, typename F>
constexpr void for_sequence(std::integer_sequence<T, S...>, F f) {
    (static_cast<void>(f(std::integral_constant<T, S>{})), ...);
}

এই ফাংশনটি একটি পূর্ণসংখ্যার ক্রম নেয় এবং লম্বাটি সিকোয়েন্সের Fদৈর্ঘ্যের যত বেশি সময় ইনস্ট্যান্ট করে ।

এটি এভাবে ব্যবহার করা হয়:

for_sequence(std::make_index_sequence<100>(), [](auto N) { /* N is from 0 to 99 */
  A<N + 1> a; /* N + 1 is from 1 to 100 */
  a.functionCalls();
});

এখানে, Nটেমপ্লেট প্যারামিটার হিসাবে প্রেরণ করা যেতে পারে কারণ এটি এমন একটি বস্তু যা একটি পূর্ণসংখ্যার ধরণের কনসেক্সট্রপ রূপান্তরকারী অপারেটর has আরও স্পষ্টভাবে, এটি std::integral_constantএকটি ক্রমবর্ধমান মান সহ।

সরাসরি উদাহরণ


3
বিতৃষ্ণা। আমি যখন এই জাতীয় টেমপ্লেট মজা দেখি তখন আমি কেবল জানি যে আমি এটির পরে কলস্ট্যাক ছাড়াই এটি ডিবাগ করতে যাচ্ছি এবং অনুমান করতে হবে যে কী চলছে ... :)
মাইকেল ডরগান

এর উদ্দেশ্য কী static_cast<void>?
আয়কসান

2
@Ayxan এড়ানোর সমস্যার যখন ল্যামডা fএকটি টাইপ ফেরৎ যে overloads কমা অপারেটর
Guillaume, Racicot

@ মিশেলডোরগান এই কারণেই আমাদের প্রয়োজন template for। ভাষা কন্সট্রাক্টগুলি এর মতো অপব্যবহার করা সর্বদা আরও বেদনাদায়ক
গিলিয়াম র্যাকিকোট

মেইল প্রোগ্রামিংয়ের জন্য টেমপ্লেটগুলির চেয়ে আমাদের গুইলিউমরাকিকোট বা আমাদের আরও ভাল বিমূর্ততা প্রয়োজন।
অজয় ব্রহ্মক্ষত্রিয়া

5

Nচাহিদা কম্পাইল-টাইম ধ্রুবক, যা সঙ্গে একটি স্বাভাবিক হতে forলুপ সম্ভব নয়।

তবে, অনেকগুলি কাজের সুযোগ রয়েছে। উদাহরণস্বরূপ, এই এসও পোস্ট দ্বারা অনুপ্রাণিত , আপনি নিম্নলিখিত মত কিছু করতে পারেন। ( একটি লাইভ ডেমো দেখুন )

template<size_t N>
class A
{
public:
    // make the member function public so that you can call with its instance
    void someFunctions()
    {
        std::cout << N << "\n";
    };
};

template<int N> struct AGenerator
{
    static void generate()
    {
        AGenerator<N - 1>::generate();
        A<N> a;
        a.someFunctions();
    }
};

template<> struct AGenerator<1>
{
    static void generate()
    {
        A<1> a;
        a.someFunctions();
    }
};

int main()
{
    // call the static member for constructing 100 A objects
    AGenerator<100>::generate();
}

প্রিন্ট 1করুন100


ইন , উপরোক্ত একটি একক ফর্মা কমে যাবে AGeneratorবর্গ (অর্থাত বিশেষজ্ঞতা এড়ানো যায়) ব্যবহার করেif constexpr( একটি লাইভ ডেমো দেখুন )

template<std::size_t N>
struct AGenerator final
{
    static constexpr void generate() noexcept
    {
        if constexpr (N == 1)
        {
            A<N> a;
            a.someFunctions();
            // .. do something more with `a`
        }
        else
        {
            AGenerator<N - 1>::generate();
            A<N> a;
            a.someFunctions();
            // .. do something more with `a`
        }
    }
};

আউটপুট :

1
2
3
4
5
6
7
8
9
10

পুনরাবৃত্তির পরিসীমা সরবরাহের ক্ষেত্রে, আপনি নিম্নলিখিতটি ব্যবহার করতে পারেন।( একটি লাইভ ডেমো দেখুন )

template<std::size_t MAX, std::size_t MIN = 1> // `MIN` is set to 1 by default
struct AGenerator final
{
    static constexpr void generate() noexcept
    {
        if constexpr (MIN == 1)
        {
            A<MIN> a;
            a.someFunctions();
            // .. do something more with `a`
            AGenerator<MAX, MIN + 1>::generate();
        }
        else if constexpr (MIN != 1 && MIN <= MAX)
        {
            A<MIN> a;
            a.someFunctions();
            // .. do something more with `a`
            AGenerator<MAX, MIN + 1>::generate();
        }
    }
};

int main()
{
    // provide the `MAX` count of looping. `MIN` is set to 1 by default
    AGenerator<10>::generate();
}

উপরের সংস্করণ হিসাবে একই আউটপুট।


4

সি ++ ২০ থেকে আপনি টেমপ্লেট ল্যাম্বডাস ব্যবহার করতে পারেন, যাতে আপনি নীচের মতো কিছু চেষ্টা করতে পারেন

[]<int ... Is>(std::integer_sequence<int, Is...>)
 { (A<Is+1>{}.functionCall(), ...); }
   (std::make_integer_sequence<int, 100>{});

নিম্নলিখিতটি একটি সম্পূর্ণ সংকলন উদাহরণ যা 0 থেকে 99 এর মধ্যে সমস্ত সংখ্যা মুদ্রণ করে

#include <utility>
#include <iostream>

int main()
 {
  []<int ... Is>(std::integer_sequence<int, Is...>)
   { (std::cout << Is << std::endl, ...); }
     (std::make_integer_sequence<int, 100>{});
 }

1

আপনি এটির একটি উপায় হ'ল টেমপ্লেট মেটা-প্রোগ্রামিং সহ এরকম কিছু সহ:

#include <iostream>

template <std::size_t N>
struct A {
  void foo() { std::cout << N << '\n'; }
};

template <std::size_t from, std::size_t to>
struct call_foo {
  void operator()() {
    if constexpr (from != to) {
      A<from + 1>{}.foo();
      call_foo<from + 1, to>{}();
    }
  }
};

int main() { call_foo<0, 100>{}(); }

0

কেবলমাত্র সম্পূর্ণতার জন্য - ক্লাস বা ফাংশনটি টেম্পলেট করার জন্য এটি কি সত্যই প্রয়োজন, যদি লুপ থেকে কেবলমাত্র ফাংশনের ব্যবহারটি ডাকা হয়?

যদি তাই হয় এবং আপনি হাত দ্বারা লিখতে চান না বুস্ট.হানা তাকান।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.