[[no_unique_address]] এবং একই ধরণের দুটি সদস্যের মান


16

আমি প্রায় খেলছি [[no_unique_address]]মধ্যে c++20

সিপ্রেফারেন্সির উদাহরণে আমাদের একটি খালি টাইপ Emptyএবং প্রকার রয়েছেZ

struct Empty {}; // empty class

struct Z {
    char c;
    [[no_unique_address]] Empty e1, e2;
};

স্পষ্টতই, আকারটি Zকমপক্ষে হওয়া উচিত 2কারণ ধরণের e1এবং e2একই রকম।

যাইহোক, আমি সত্যিই Zআকার চাই 1। এটি আমাকে ভাবছে, Emptyঅতিরিক্ত টেম্পলেট প্যারামিটার সহ কিছু মোড়ক ক্লাসে মোড়ানো সম্পর্কে যা বিভিন্ন ধরণের e1এবং প্রয়োগ করে e2

template <typename T, int i>
struct Wrapper : public T{};

struct Z1 {
    char c;
    [[no_unique_address]] Wrapper<Empty,1> e1;
    [[no_unique_address]] Wrapper<Empty,2> e2;
};

দুর্ভাগ্যক্রমে sizeof(Z1)==2,। আকারটি এক Z1হওয়ার কৌশল আছে কি ?

আমি এই পরীক্ষার করছি gcc version 9.2.1এবংclang version 9.0.0


আমার আবেদনে আমার কাছে ফর্মের প্রচুর খালি প্রকার রয়েছে

template <typename T, typename S>
struct Empty{
    [[no_unique_address]] T t;
    [[no_unique_address]] S s;
};

যা একটি খালি টাইপ যদি Tএবং Sএছাড়াও খালি ধরনের এবং স্বতন্ত্র হয়! আমি এই ধরনের এমনকি যদি খালি হতে চান Tএবং Sএকই ধরনের হয়।


2
Tনিজের মধ্যে টেম্পলেট যুক্তি যুক্ত করার বিষয়ে কী ? এটি স্বতন্ত্র প্রকারের তৈরি করতে পারে। এই মুহুর্তে উভয়ই Wrapperউত্তরাধিকার সূত্রে Tআপনাকে পিছনে রেখেছে ...
ম্যাক্স ল্যানঘফ

@ ম্যাক্সলানঘফ একটি টেমপ্লেট যুক্তি যুক্ত করে আপনার অর্থ কী T? এখনই, Tএকটি টেমপ্লেট যুক্তি।
tom

থেকে উত্তরাধিকারী না T
এভগ

@ ইভগ এখানে কোন পার্থক্য করে না।
এরেরিকা

2
: শুধু কারণ এটি 1 চেয়ে বড় এটা খালি নয় এমন দেখা যায় না coliru.stacked-crooked.com/a/51aa2be4aff4842e
Deduplicator

উত্তর:


6

যা একটি খালি টাইপ যদি Tএবং Sএছাড়াও খালি ধরনের এবং স্বতন্ত্র হয়! আমি এই ধরনের এমনকি যদি খালি হতে চান Tএবং Sএকই ধরনের হয়।

আপনি এটি পেতে পারেন না। প্রযুক্তিগতভাবে বলতে গেলে, আপনি এমনকি গ্যারান্টি দিতে পারবেন না যে এটি খালি হবে Tএবং এমনকি Sবিভিন্ন খালি প্রকারের। মনে রাখবেন: no_unique_addressএকটি বৈশিষ্ট্য; বস্তুর আড়াল করার এর ক্ষমতা সম্পূর্ণরূপে বাস্তবায়ন নির্ভর। একটি স্ট্যান্ডার্ড দৃষ্টিকোণ থেকে, আপনি খালি বস্তুর আকার প্রয়োগ করতে পারবেন না।

সি ++ ২০ টি বাস্তবায়ন পরিপক্ক হওয়ার সাথে সাথে আপনার ধরে নেওয়া উচিত যে [[no_unique_address]]খালি বেস অপ্টিমাইজেশনের নিয়মগুলি অনুসরণ করবে। যথা, যতক্ষণ না একই ধরণের দুটি অবজেক্ট সাবোবজেক্ট না হয়, আপনি সম্ভবত লুকিয়ে থাকার আশা করতে পারেন। তবে এই মুহুর্তে, এটি ধরণের পাত্র-ভাগ্য।

একই ধরণের সুনির্দিষ্ট ক্ষেত্রে Tএবং Sএটি কেবল সম্ভব নয়। "ন_ইউনিক_এড্রেস" নামটির অন্তর্নিহিত সত্ত্বেও, বাস্তবতাটি হ'ল সি ++ এর জন্য একই ধরণের বস্তুগুলিকে দুটি পয়েন্টার দেওয়া হয়, সেই পয়েন্টারগুলি একই বস্তুর দিকে নির্দেশ করে বা বিভিন্ন ঠিকানা দেয়। আমি এটিকে "অনন্য পরিচয়ের নিয়ম" বলি এবং no_unique_addressএটি প্রভাবিত করে না। থেকে [intro.object] / 9 :

বিট-ফিল্ড নয় এমন ওভারল্যাপিং লাইফটাইমযুক্ত দুটি বস্তুর একই ঠিকানা থাকতে পারে যদি অন্যের মধ্যে বাসা বেঁধে রাখা হয়, বা যদি কমপক্ষে একটি শূন্য আকারের একটি সাবওবজেক্ট এবং সেগুলি বিভিন্ন ধরণের হয় ; অন্যথায়, তাদের স্বতন্ত্র ঠিকানা রয়েছে এবং স্টোরেজের বাইটগুলি পৃথক করে।

[[no_unique_address]]শূন্য আকারের হিসাবে ঘোষিত খালি প্রকারের সদস্যরা , তবে একই ধরণের থাকা এটিকে অসম্ভব করে তোলে।

প্রকৃতপক্ষে, এটি সম্পর্কে চিন্তা করে, বাসা বাঁধার মাধ্যমে খালি প্রকারটি আড়াল করার চেষ্টা করা এখনও অনন্য পরিচয়ের নিয়ম লঙ্ঘন করে। আপনার Wrapperএবং Z1কেস বিবেচনা করুন । z1একটি উদাহরণ দেওয়া যা দেওয়া Z1, এটি পরিষ্কার যে z1.e1এবং z1.e2বিভিন্ন ধরণের বিভিন্ন বস্তু। তবে এর z1.e1মধ্যে বাসা থেকে বাসা বাঁধে z1.e2না। তারা বিভিন্ন ধরনের আছে, যখন (Empty&)z1.e1এবং (Empty&)z1.e2হয় না বিভিন্ন ধরনের। তবে তারা বিভিন্ন বস্তুর প্রতি নির্দেশ দেয়।

এবং অনন্য পরিচয়ের নিয়ম অনুসারে, তাদের অবশ্যই পৃথক ঠিকানা থাকতে হবে। সুতরাং যদিও e1এবং e2নামমাত্র বিভিন্ন ধরণের, তাদের অভ্যন্তরীণ অবশ্যই একই সাবজেক্টযুক্ত অন্যান্য সাবওবজেক্টগুলির বিরুদ্ধে অনন্য পরিচয় মানতে হবে। Recursively।

আপনি যা চান তা সি ++ এ কেবল অসম্ভব কারণ এটি বর্তমানে আপনি যেমন চেষ্টা করেন তা নির্বিশেষে দাঁড়িয়ে থাকে।


দুর্দান্ত ব্যাখ্যা, অনেক অনেক ধন্যবাদ!
tom

2

আমি যতদূর বলতে পারি, যদি আপনি উভয় সদস্য রাখতে চান তবে এটি সম্ভব নয়। প্রকারটি একই এবং খালি থাকলে আপনি কেবল বিশেষজ্ঞের একজন সদস্য থাকতে পারেন:

template <typename T, typename S, typename = void>
struct Empty{
    [[no_unique_address]] T t;
    [[no_unique_address]] S s;

    constexpr T& get_t() noexcept { return t; };
    constexpr S& get_s() noexcept { return s; };
};

template<typename TS>
struct Empty<TS, TS, typename std::enable_if_t<std::is_empty_v<TS>>>{
    [[no_unique_address]] TS ts;

    constexpr TS& get_t() noexcept { return ts; };
    constexpr TS& get_s() noexcept { return ts; };
};

অবশ্যই, সদস্যদের ব্যবহার করে এমন অন্যান্য প্রোগ্রামের ক্ষেত্রে কেবলমাত্র একজন সদস্য রয়েছে এমন মামলা মোকাবেলায় পরিবর্তন করা দরকার। এই ক্ষেত্রে কোন সদস্যটি ব্যবহার করা উচিত তা বিবেচ্য নয় - সর্বোপরি, এটি কোনও রাজ্যহীন বস্তু যার কোনও অনন্য ঠিকানা নেই। প্রদর্শিত সদস্য ফাংশনগুলি যে সহজ করা উচিত।

দুর্ভাগ্যক্রমে sizeof(Empty<Empty<A,A>,A>{})==2যেখানে এ সম্পূর্ণরূপে খালি কাঠামো।

খালি জোড়া পুনরুক্তিযোগ্য সংক্ষেপণ সমর্থন করতে আপনি আরও বিশেষত্ব প্রবর্তন করতে পারেন:

template<class TS>
struct Empty<Empty<TS, TS>, TS, typename std::enable_if_t<std::is_empty_v<TS>>>{
    [[no_unique_address]] Empty<TS, TS> ts;

    constexpr Empty<TS, TS>& get_t() noexcept { return ts; };
    constexpr TS&            get_s() noexcept { return ts.get_s(); };
};

template<class TS>
struct Empty<TS, Empty<TS, TS>, typename std::enable_if_t<std::is_empty_v<TS>>>{
    [[no_unique_address]] Empty<TS, TS> ts;

    constexpr TS&            get_t() noexcept { return ts.get_t(); };
    constexpr Empty<TS, TS>& get_s() noexcept { return ts; };
};

আরও বেশি কিছু সংকোচনের জন্য Empty<Empty<A, char>, A>

template <typename T, typename S>
struct Empty<Empty<T, S>, S, typename std::enable_if_t<std::is_empty_v<S>>>{
     [[no_unique_address]] Empty<T, S> ts;

    constexpr Empty<T, S>& get_t() noexcept { return ts; };
    constexpr S&           get_s() noexcept { return ts.get_s(); };
};

template <typename T, typename S>
struct Empty<Empty<S, T>, S, typename std::enable_if_t<std::is_empty_v<S>>>{
     [[no_unique_address]] Empty<S, T> st;

    constexpr Empty<S, T>& get_t() noexcept { return st; };
    constexpr S&           get_s() noexcept { return st.get_t(); };
};


template <typename T, typename S>
struct Empty<T, Empty<T, S>, typename std::enable_if_t<std::is_empty_v<T>>>{
     [[no_unique_address]] Empty<T, S> ts;

    constexpr T&           get_t() noexcept { return ts.get_t(); };
    constexpr Empty<T, S>  get_s() noexcept { return ts; };
};

template <typename T, typename S>
struct Empty<T, Empty<S, T>, typename std::enable_if_t<std::is_empty_v<T>>>{
     [[no_unique_address]] Empty<S, T> st;

    constexpr T&           get_t() noexcept { return st.get_s(); };
    constexpr Empty<S, T>  get_s() noexcept { return st; };
};

এটি দুর্দান্ত, তবে এখনও দুর্ভাগ্যবশত sizeof(Empty<Empty<A,A>,A>{})==2যেখানে Aসম্পূর্ণ ফাঁকা কাঠামো রয়েছে।
tom

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