আমি কীভাবে সি ++ তে টাইপ তালিকার কার্টেসিয়ান পণ্য তৈরি করতে পারি?


26

স্ব বর্ণনামূলক।

মূলত, বলুন আমার মতো টাইপ তালিকাগুলি রয়েছে:

using type_list_1 = type_list<int, somestructA>;
using type_list_2 = type_list<somestructB>;
using type_list_3 = type_list<double, short>;

এগুলি টাইপ তালিকার বিভিন্ন সংখ্যা হতে পারে।

আমি কীভাবে কার্টেসিয়ান পণ্যটির টাইপলিস্ট পেতে পারি?

result = type_list<
type_list<int, somestructB, double>,
type_list<int, somestructB, short>,
type_list<somestructA, somestructB, double>,
type_list<somestructA, somestructB, short>
>;

এখানে যেমন দেওয়া হয়েছে দ্বি-দ্বি কার্টেসিয়ান পণ্য কীভাবে তৈরি করতে হবে তা নিয়ে আমি ছটফট করেছিলাম: টাইপ তালিকার কার্টেসিয়ান পণ্য কীভাবে তৈরি করবেন? , তবে এন উপায়টি তেমন তুচ্ছ বলে মনে হচ্ছে না।

আপাতত আমি চেষ্টা করছি ...

template <typename...> struct type_list{};

// To concatenate
template <typename... Ts, typename... Us>
constexpr auto operator|(type_list<Ts...>, type_list<Us...>) {
   return type_list{Ts{}..., Us{}...};
}

template <typename T, typename... Ts, typename... Us>
constexpr auto cross_product_two(type_list<T, Ts...>, type_list<Us...>) {
    return (type_list<type_list<T,Us>...>{} | ... | type_list<type_list<Ts, Us>...>{});
}

template <typename T, typename U, typename... Ts>
constexpr auto cross_product_impl() {
    if constexpr(sizeof...(Ts) >0) {
        return cross_product_impl<decltype(cross_product_two(T{}, U{})), Ts...>();
    } else {
        return cross_product_two(T{}, U{});
    }
}

আমি কেবল এটিই বলব যে এটি সঠিকভাবে পাওয়া কতটা কঠিন তা বিবেচনা করে, ব্যারি কর্তৃক উত্তরের মতো কেবল বুস্ট ব্যবহার করুন। দুর্ভাগ্যক্রমে আমাকে একটি হাত ঘূর্ণিত পদ্ধতির সাথে আটকে থাকতে হবে কারণ বুস্ট ব্যবহার করা বা না করা কোনও সিদ্ধান্ত যা অন্য কোথাও থেকে আসে :(


8
ওফ, আপনি শাস্তির পেটুক 😏
রেস

আমি এটিকে চুষতে চাই, তবে আপনি কী দ্বি-উপায় কার্তেসিয়ান পণ্যটি এমনভাবে পরিবর্তন করতে পারেন যে: 1) প্রথম টাইপলিস্ট আসলে 1 টাইপের টাইপলিস্টের টাইপলিস্ট; ২) টাইপলিস্ট থেকে দুই প্রকারের সংমিশ্রণের পরিবর্তে, মেটাফাংশনটি দ্বিতীয় টাইপ থেকে প্রথম টাইপলিস্টের "সন্তানের" তালিকায় (কার্টেসিয়ান-প্রোডাক্ট-ওয়ে) টাইপ করে? যদি এটি সম্ভব হয় তবে সমস্যাগুলি সহজেই পুনরাবৃত্তির অ্যালগরিদম দিয়ে সমাধান করা যেতে পারে।
স্মিতসিন

1
পুনরাবৃত্তির বাস্তবায়নে আসল অসুবিধাটি হ'ল cartesian_productধরণের তালিকাগুলির একটি তালিকা এবং প্রতিটি পুনরাবৃত্তির পদক্ষেপে আপনি প্রতিটি অভ্যন্তরের প্রকারের তালিকায় স্টাফ যুক্ত করতে চান। প্যাকের দ্বিতীয় প্যাকিং স্তরে উঠতে কিছুটা ছাড় নেওয়া লাগে ...
ম্যাক্স ল্যাংফোফ

1
আমার ধারণা আপনি কোনও এন-ডাইমেনশনাল "টাইপ স্পেস" হিসাবে যেখানে আপনি প্রতিটি "টাইপ গ্রিড পয়েন্ট" অতিক্রম করতে চান তা দেখে আপনি এটি "রৈখিক" প্রয়োগ করতে পারেন। আপনি গ্রিড পয়েন্টগুলির সংখ্যা গণনা করুন, তারপরে আপনি এটিকে ঠিক এমনভাবে অতিক্রম করবেন যেমন আপনি একটি সমতল এনডি অ্যারের মাধ্যমে এবং প্রতিটি গ্রিড পয়েন্টে প্রকারগুলি গণনা করতে পারেন। কিছু বিবেচনা করার জন্য ...
ম্যাক্স ল্যাঙ্গোফ

1
@ ম্যাক্স ল্যাংহোফ " সি ++ 17 তে টিপলসের কার্টেসিয়ান পণ্য " এর পংক্তিতে কিছু ?
Deduplicator

উত্তর:


14

বুস্ট.এমপি 11 এর সাথে এটি একটি সংক্ষিপ্ত ওয়ান-লাইনার (সর্বদা হিসাবে):

using result = mp_product<
    type_list,
    type_list_1, type_list_2, type_list_3>;

ডেমো


1
পবিত্র গাভী ... তবে আমি উল্লেখ করতে বাধ্য যে (গডবোল্টে প্রতিটি কোড বেশ কয়েকবার নমুনা নিচ্ছেন) এমপি 11 সংস্করণটি সংকলন করতে প্রায় দ্বিগুণ সময় নেয়। নিশ্চিত নয় যে ওভারহেডের কতটা নিজেই বুস্ট শিরোনামকে পার্স করছে এবং
কতগুলি

1
পুনঃটুইট 1.5x যদি আপনি কেবল algorithm.hppএমপি 11 এর পরিবর্তে অন্তর্ভুক্ত করেন । এবং তারপরেও আমরা 0.08s বনাম 0.12s বলছি। এটি লিখতে আমার কতক্ষণ লেগেছিল তা সম্পর্কে ফ্যাক্ট করতে হবে।
ব্যারি

8
@ ব্যারি: আপনার সাথে 100% সহ একটি সফ্টওয়্যার ইঞ্জিনিয়ারিং অবস্থান থেকে। হ্যান্ড রোলড অ্যাপ্রোম বনাম এটি পড়া কত সহজ There এছাড়াও গ্রন্থাগার সমাধানের সঠিকতা নিশ্চিত করার জন্য কোনও পরীক্ষার দরকার নেই। সামগ্রিকভাবে কম কোড এবং উচ্চতর আত্মবিশ্বাসের ফলে তার আজীবন কম রক্ষণাবেক্ষণ ব্যয় হবে।
অ্যান্ডি

আমি সম্মতি জানাই এটি বেশ সহজ তবে দুর্ভাগ্যক্রমে এমন দল রয়েছে যা উত্সাহ দিয়েছিল।
থিমজায়ালিয়াং

এমন সমস্ত দল রয়েছে যা সবকিছুর উপর নির্ভর করে। এটি এটি ব্যবহার না করার কোনও কারণ নয়।
তোমাজ কানাব্রভা

13

ঠিক আছে বুঝেছি. এটি সুন্দর নয় তবে এটি কাজ করে:

template<class ... T>
struct type_list{};

struct somestructA{};
struct somestructB{};

using type_list_1 = type_list<int, somestructA, char>;
using type_list_2 = type_list<somestructB>;
using type_list_3 = type_list<double, short, float>;

template<class TL1, class TL2>
struct add;

template<class ... T1s, class ... T2s>
struct add<type_list<T1s...>, type_list<T2s...>>
{
    using type = type_list<T1s..., T2s...>;
};

template<class ... TL>
struct concat;

template<class TL, class ... TLs>
struct concat<TL, TLs...>
{
    using type = typename add<TL, typename concat<TLs...>::type>::type;
};

template<class TL>
struct concat<TL>
{
    using type = TL;
};

static_assert(std::is_same_v<type_list<int, somestructA, char, double, short, float>, typename add<type_list_1, type_list_3>::type>);

template<class TL1, class TL2>
struct multiply_one;

// Prepends each element of T1 to the list T2.
template<class ... T1s, class ... T2s>
struct multiply_one<type_list<T1s...>, type_list<T2s...>>
{
    using type = typename concat<type_list<type_list<T1s, T2s...>...>>::type;
};

static_assert(std::is_same_v<
    type_list<
        type_list<int, double, short, float>,
        type_list<somestructA, double, short, float>,
        type_list<char, double, short, float>
        >,
    typename multiply_one<type_list_1, type_list_3>::type>);

// Prepends each element of TL to all type lists in TLL.
template<class TL, class TLL>
struct multiply_all;

template<class TL, class ... TLs>
struct multiply_all<TL, type_list<TLs...>>
{
    using type = typename concat<typename multiply_one<TL, TLs>::type...>::type;
};

static_assert(std::is_same_v<
    type_list<
        type_list<int, double, short, float>,
        type_list<somestructA, double, short, float>,
        type_list<char, double, short, float>
        >,
    typename multiply_all<type_list_1, type_list<type_list_3>>::type>);

static_assert(std::is_same_v<
    type_list<
        type_list<int, somestructB>,
        type_list<somestructA, somestructB>,
        type_list<char, somestructB>,
        type_list<int, double, short, float>,
        type_list<somestructA, double, short, float>,
        type_list<char, double, short, float>
        >,
    typename multiply_all<type_list_1, type_list<type_list_2, type_list_3>>::type>);

template<class TL, class ... TLs>
struct cartesian_product
{
    using type = typename multiply_all<TL, typename cartesian_product<TLs...>::type>::type;
};

template<class ... Ts>
struct cartesian_product<type_list<Ts...>>
{
    using type = type_list<type_list<Ts>...>;
};


using expected_result = type_list<
    type_list<int, somestructB, double>,
    type_list<somestructA, somestructB, double>,
    type_list<char, somestructB, double>,
    type_list<int, somestructB, short>,
    type_list<somestructA, somestructB, short>,
    type_list<char, somestructB, short>,
    type_list<int, somestructB, float>,
    type_list<somestructA, somestructB, float>,
    type_list<char, somestructB, float>
>;

static_assert(std::is_same_v<expected_result,
    cartesian_product<type_list_1, type_list_2, type_list_3>::type>);

https://godbolt.org/z/L5eamT

আমি static_assertসেখানে আমার নিজস্ব পরীক্ষা রেখেছি ... ভাল, আমি আশা করি তারা সহায়তা করবে।

এছাড়াও, আমি নিশ্চিত একটি ভাল সমাধান আছে আছে। তবে এটি ছিল সুস্পষ্ট "আমি জানি এটি শেষ পর্যন্ত লক্ষ্যে পৌঁছাবে" পথটি। অবশেষে আমাকে একটি concatবা বাছাইয়ের অবলম্বন করতে হয়েছিল , আমি নিশ্চিত যে এটি বেশিরভাগ ক্রাফট এড়িয়ে যাওয়ার জন্য অনেক আগে ব্যবহার করা যেতে পারে।


4
টেমপ্লেট প্রোগ্রামিং যা আমি অনুসরণ করতে পারি। সেটা খুবই ভালো. আমি আজ কিছু শিখেছি।
জেরি যেরেমিয়া

যোগ দুটি টাইপ_লিস্ট লাগে। কনকটে যোগ করতে আপনি কীভাবে একাধিক ধরণের তালিকা পাস করছেন?
থিমজিক্যাল্যাং

@ থেমাজিক্যাল্যাং ভাল-স্পটেড, এটি একটি বাগ (যা পরীক্ষায় জড়িত সমস্ত তালিকা কেবল দৈর্ঘ্য 2 ছিল না)। এর বাইরে নয়, ...পুনরাবৃত্তির concatকলটির ভিতরে যেতে হবে । উত্তর (পরীক্ষার মামলা সহ) সংশোধন করা হয়েছে। নির্ভুলতা প্রত্যাশা সম্পর্কিত ব্যারি সঠিক প্রমাণিত করে :)
ম্যাক্স ল্যাংফোফ

কারটিশিয়ান পণ্য কলটি মূলত একাধিক_ একক নয়?
থিমজিক্যাল্যাং

@ থেমেজিক্যালিয়াং নং cartesian_productপুনরাবৃত্তি কার্যকর করে। multiply_allপ্যাকটিতে multiply_oneপ্রতিটি ধরণের তালিকার জন্য একটি করে TLscartesian_product::typeটাইপ তালিকার একটি তালিকা। multiply_allএকটি ধরণের তালিকা এবং ধরণের তালিকার একটি তালিকা নেয়। multiply_oneদুই ধরনের তালিকা লাগে a1, a2, a3এবং b1, b2, b3এবং সৃষ্টি a1, b1, b2, b3, a2, b1, b2, b3, a3, b1, b2, b3। আপনি সিদ্ধান্তগ্রহণ (এই দুই স্তরের প্রয়োজন multiply_all, multiply_one) কারণ আপনি "variadicness" এর দুই স্তর নিচে নেমে প্রয়োজন, প্রশ্নে আমার প্রথম মন্তব্য দেখুন।
ম্যাক্স ল্যাঙ্গোফ

9

আবার উদ্ধারে উদ্ধৃতিগুলি ভাঁজ করুন

template<typename... Ts>
typelist<typelist<Ts>...> layered(typelist<Ts...>);

template<typename... Ts, typename... Us>
auto operator+(typelist<Ts...>, typelist<Us...>)
    -> typelist<Ts..., Us...>;

template<typename T, typename... Us>
auto operator*(typelist<T>, typelist<Us...>)
    -> typelist<decltype(T{} + Us{})...>;

template<typename... Ts, typename TL>
auto operator^(typelist<Ts...>, TL tl)
    -> decltype(((typelist<Ts>{} * tl) + ...));

template<typename... TLs>
using product_t = decltype((layered(TLs{}) ^ ...));

এবং তুমি করে ফেলেছ. ও (1) তাত্ক্ষণিক গভীরতা থাকার ক্ষেত্রে এটির পুনরাবৃত্তি অতিরিক্ত অতিরিক্ত সুবিধা রয়েছে।

struct A0;
struct A1;
struct B0;
struct B1;
struct C0;
struct C1;
struct C2;

using t1 = typelist<A0, A1>;
using t2 = typelist<B0, B1>;
using t3 = typelist<C0, C1, C2>; 

using p1 = product_t<t1, t2>;
using p2 = product_t<t1, t2, t3>;

using expect1 = typelist<typelist<A0, B0>,
                         typelist<A0, B1>,
                         typelist<A1, B0>,
                         typelist<A1, B1>>;

using expect2 = typelist<typelist<A0, B0, C0>,
                         typelist<A0, B0, C1>,
                         typelist<A0, B0, C2>,
                         typelist<A0, B1, C0>,
                         typelist<A0, B1, C1>,
                         typelist<A0, B1, C2>,
                         typelist<A1, B0, C0>,
                         typelist<A1, B0, C1>,
                         typelist<A1, B0, C2>,
                         typelist<A1, B1, C0>,
                         typelist<A1, B1, C1>,
                         typelist<A1, B1, C2>>;

static_assert(std::is_same_v<p1, expect1>);
static_assert(std::is_same_v<p2, expect2>);

এটা আমার ষড়যন্ত্র করে। এটিকে টিএল 1 * টিএল 2 * টিএল 3 = ক্রসপর্ড্ট ফলাফল হিসাবে উপস্থাপন করার কোনও উপায় আছে কি?
থিমজিক্যাল্যাং

@ থেমজিলিক্য্যাং "ক্রস প্রোডাক্ট ফলাফল" বলতে কী বোঝ?
পাসারের দ্বারা

মূলত পরিবর্তে using result = product_t<t1,t2,t3>... এটি উপস্থাপন করার কিছু উপায় using result = decltype(t1{} * t2{} * t3{});। হুঁ, এখন এটি যেহেতু এটি সম্পর্কে চিন্তা করে, এটি যেহেতু decltypeঅনিবার্য, কেবলমাত্র আপনার দেওয়া উপনামটি ব্যবহার করা আরও স্বজ্ঞাত।
থিমজিক্যালিয়াং

মজাদার! অপারেটর ওভারলোডিং ব্যবহার করে আমার যে পুনরাবৃত্তিগুলি করতে হয়েছিল তার পরিবর্তে আপনি ভাঁজ প্রকাশ করতে পারেন। এটি আরও সংক্ষিপ্ত করে তোলে। আমি এটি পরের বারের জন্য মনে রাখব!
ম্যাক্স ল্যাংফোফ

@ পাসসারবি এই সমস্ত সহায়ক অপারেটর এবং ফাংশনগুলির কি একই নামস্থানে থাকা দরকার? আমি সমস্ত কিছু একটি নেমস্পেসের ভিতরে andোকানোর এবং বাইরের নেমস্পেসের থেকে একটি উপনাম ব্যবহার করে product_t অ্যাক্সেস করার সমস্যা পাচ্ছি।
থিমজায়ালিয়াং
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.