টি এল; ডিআর
এই পুরো পোস্টটি পড়ার চেষ্টা করার আগে জেনে রাখুন:
- উপস্থাপিত ইস্যুটির একটি সমাধান আমি নিজেই খুঁজে পেয়েছি তবে বিশ্লেষণটি সঠিক কিনা তা জানতে আমি এখনও আগ্রহী;
- আমি সমাধানটি একটি
fameta::counter
ক্লাসে প্যাকেজ করেছি যা কয়েকটা বাকী বাচ্চা সমাধান করে। আপনি এটি গিথুবে খুঁজে পাবেন ; - আপনি গডবোল্ট নিয়ে কাজ করতে পারেন ।
কিভাবে এটি সব শুরু
ফিলিপ রোজেন আবিষ্কার করেছেন / আবিষ্কার করেছেন, ২০১৫ সালে, টাইম কাউন্টারগুলি সংকলনকারী কালো যাদুটি সি ++ তে রয়েছে , তখন আমি ডিভাইসটি নিয়ে হালকাভাবে আচ্ছন্ন হয়ে পড়েছিলাম, তাই যখন সিডাব্লুজি সিদ্ধান্ত নিয়েছিল যে কার্যকারিতাটিই যেতে হবে তখন আমি হতাশ হয়েছিলাম, তবে এখনও আশাবাদী যে তাদের মন তাদের কয়েকটি বাধ্যতামূলক ব্যবহারের কেস দেখিয়ে পরিবর্তন করা যেতে পারে।
তারপরে, কয়েক বছর আগে আমি আবার সেই জিনিসটি আবার দেখার জন্য সিদ্ধান্ত নিয়েছি, যাতে উবারসুইচ এস বাসা বেঁধে দেওয়া যায় - আমার মতে একটি আকর্ষণীয় ব্যবহারের কেস - কেবল এটি আবিষ্কার করতে যে এটি নতুন সংস্করণগুলির সাথে আর কাজ করবে না discover উপলব্ধ সংকলকগুলি, যদিও 2121 সংখ্যাটি খোলা অবস্থায় ছিল (এবং এখনও রয়েছে ): কোডটি সংকলন করবে, তবে কাউন্টারটি বাড়বে না।
সমস্যা রোজেনের ওয়েবসাইটে এবং সম্প্রতি স্ট্যাকওভারফ্লোতেও রিপোর্ট করা হয়েছে : সি ++ কি সংকলন-সময় কাউন্টারগুলিকে সমর্থন করে?
কিছু দিন আগে আমি আবার সমস্যাগুলি সমাধান করার চেষ্টা করব
আমি বুঝতে চেয়েছিলাম যে সংকলকগুলিতে কী পরিবর্তন হয়েছে যা আপাতদৃষ্টিতে এখনও বৈধ সি ++ করেছে, আর কাজ করে না। এ লক্ষ্যে, আমি কারও পক্ষে এটি সম্পর্কে কথা বলার জন্য প্রশস্ত এবং আন্তঃস্বল্প দূরত্বে অনুসন্ধান করেছি, কিন্তু কোন ফলসই হয়নি। তাই আমি পরীক্ষা-নিরীক্ষা শুরু করেছি এবং কিছু সিদ্ধান্তে পৌঁছেছি, আমি এখানে আশেপাশের আরও জ্ঞাত-বুদ্ধিমানের থেকে একটি প্রতিক্রিয়া পাওয়ার আশায় এখানে উপস্থাপন করছি।
নীচে আমি স্পষ্টতার জন্য রোজেনের মূল কোডটি উপস্থাপন করছি। এটি কীভাবে কাজ করে তার ব্যাখ্যার জন্য, দয়া করে তার ওয়েবসাইটটি দেখুন :
template<int N>
struct flag {
friend constexpr int adl_flag (flag<N>);
};
template<int N>
struct writer {
friend constexpr int adl_flag (flag<N>) {
return N;
}
static constexpr int value = N;
};
template<int N, int = adl_flag (flag<N> {})>
int constexpr reader (int, flag<N>) {
return N;
}
template<int N>
int constexpr reader (float, flag<N>, int R = reader (0, flag<N-1> {})) {
return R;
}
int constexpr reader (float, flag<0>) {
return 0;
}
template<int N = 1>
int constexpr next (int R = writer<reader (0, flag<32> {}) + N>::value) {
return R;
}
int main () {
constexpr int a = next ();
constexpr int b = next ();
constexpr int c = next ();
static_assert (a == 1 && b == a+1 && c == b+1, "try again");
}
জি ++ এবং ঝনঝন ++ উভয়ই সাম্প্রতিক-ইশ সংকলকগুলির সাথে next()
সর্বদা 1 টি ফিরে আসে a এই ফাংশনগুলি ডিফল্ট প্যারামিটারগুলির পুনরায় মূল্যায়নকে ট্রিগার করে না, এভাবে কখনও নতুন ফাংশন ইনস্ট্যান্ট করে না তবে সর্বদা পূর্ববর্তী তাত্ক্ষণিকগুলিকে উল্লেখ করে।
প্রথম প্রশ্ন
- আপনি কি আমার এই নির্ণয়ের সাথে সত্যই একমত?
- যদি হ্যাঁ, এই নতুন আচরণটি কি মানদণ্ড দ্বারা বাধ্যতামূলক? আগেরটি কি বাগ ছিল?
- তা না হলে সমস্যা কী?
উপরের কথাটি মাথায় রেখে আমি চারপাশে একটি কাজ করে হাজির হয়েছি: প্রতিটি next()
আহ্বানকে মনোোটোনিকভাবে বাড়ানো অনন্য আইডি দিয়ে চিহ্নিত করুন, কলিগুলিতে পৌঁছানোর জন্য, যাতে কোনও কল একই না হয়, অতএব সংকলককে সমস্ত যুক্তি পুনরায় মূল্যায়ন করতে বাধ্য করা প্রতি বার.
এটি করার জন্য এটি বোঝা বলে মনে হচ্ছে, তবে এটির কথা চিন্তা করে কেউ কেবল কোনও ফাংশনের মতো ম্যাক্রোতে লুকানো স্ট্যান্ডার্ড __LINE__
বা __COUNTER__
পছন্দসই (যেখানেই উপলভ্য) ম্যাক্রো ব্যবহার করতে পারে counter_next()
।
সুতরাং আমি নিম্নলিখিতগুলি নিয়ে এসেছি, আমি সর্বাধিক সরলীকৃত ফর্মটিতে উপস্থাপন করি যা আমি পরে যে সমস্যাটি সম্পর্কে কথা বলব তা দেখায়।
template <int N>
struct slot;
template <int N>
struct slot {
friend constexpr auto counter(slot<N>);
};
template <>
struct slot<0> {
friend constexpr auto counter(slot<0>) {
return 0;
}
};
template <int N, int I>
struct writer {
friend constexpr auto counter(slot<N>) {
return I;
}
static constexpr int value = I-1;
};
template <int N, typename = decltype(counter(slot<N>()))>
constexpr int reader(int, slot<N>, int R = counter(slot<N>())) {
return R;
};
template <int N>
constexpr int reader(float, slot<N>, int R = reader(0, slot<N-1>())) {
return R;
};
template <int N>
constexpr int next(int R = writer<N, reader(0, slot<N>())+1>::value) {
return R;
}
int a = next<11>();
int b = next<34>();
int c = next<57>();
int d = next<80>();
গডবোল্টের উপরের ফলাফলগুলি আপনি পর্যবেক্ষণ করতে পারেন , যা আমি অলসদের জন্য স্ক্রিনশট করেছি।
এবং আপনি দেখতে পাচ্ছেন, ট্রাঙ্ক জি ++ এবং ঝনঝন ++ সহ 7.0.0 পর্যন্ত এটি কাজ করে! , প্রত্যাশা হিসাবে কাউন্টারটি 0 থেকে 3 থেকে বৃদ্ধি পায় তবে ঝাঁকুনি ++ সংস্করণ 7.0.0 এর উপরে এটির সাথে হয় না ।
আঘাতের অপমানের জন্য, আমি আসলে মিশ্রণটিতে একটি "প্রসঙ্গ" পরামিতি যুক্ত করে সংস্করণ 7.0.0 ক্র্যাশ পর্যন্ত ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ কম কম পর্যন্ত অবধি কমিয়ে আনার ব্যবস্থা করেছি such কোনও নতুন প্রসঙ্গ নির্ধারণ করা হলে যে কোনও সময় পুনরায় চালু করা হবে, এটি সম্ভাব্য অসীম পরিমাণ কাউন্টার ব্যবহারের সম্ভাবনার জন্য উন্মুক্ত। এই বৈকল্পিকের সাথে, ঝাঁকুনি ++ উপরের সংস্করণ 7.0.0 ক্র্যাশ হয় না, তবে এখনও প্রত্যাশিত ফলাফল তৈরি করে না। Godbolt এ লাইভ ।
কী চলছে তা সম্পর্কে কোনও ধারণা না পেয়ে, আমি সিপ্পিনসাইটস.আইও ওয়েবসাইটটি আবিষ্কার করেছি , এটি কীভাবে এবং কখন টেমপ্লেটগুলি ইনস্ট্যান্ট হয় তা দেখতে দেয়। আমি যা মনে করি সে পরিষেবাটি ব্যবহার করে হ'ল ঝনক ++ প্রকৃতপক্ষে যখনই তাত্ক্ষণিক হয় তখন কোনও কার্যকারিতা সংজ্ঞায়িত করে না ।friend constexpr auto counter(slot<N>)
writer<N, I>
counter(slot<N>)
ইতিমধ্যে তাত্ক্ষণিকভাবে হওয়া উচিত যে কোনও প্রদত্ত এনকে স্পষ্টভাবে কল করার চেষ্টা করা এই অনুমানকে ভিত্তি বলে মনে হচ্ছে।
তবে, যদি আমি writer<N, I>
প্রদত্ত যে কোনওটির জন্য স্পষ্টভাবে তাত্ক্ষণিকভাবে চেষ্টা করার চেষ্টা করি N
এবং I
এটি ইতিমধ্যে তাত্ক্ষণিকভাবে হওয়া উচিত ছিল, তবে ঝনক ++ একটি নতুন সংজ্ঞায়িত সম্পর্কে অভিযোগ করে friend constexpr auto counter(slot<N>)
।
উপরেরটি পরীক্ষা করতে, আমি পূর্ববর্তী উত্স কোডে আরও দুটি লাইন যুক্ত করেছি।
int test1 = counter(slot<11>());
int test2 = writer<11,0>::value;
গডবোল্টে আপনি নিজের জন্য এটি সব দেখতে পারেন । স্ক্রিনশট নীচে।
সুতরাং, দেখা যায় যে ঝনঝন ++ বিশ্বাস করে যে এটি এমন কোনও সংজ্ঞা দিয়েছে যা এটি বিশ্বাস করে যে এটি সংজ্ঞায়িত হয়নি , কোন ধরণের আপনার মাথাকে স্পিন করে তোলে, তাই না?
প্রশ্ন দ্বিতীয় ব্যাচ
- আমার কার্যত আইনী সি ++ আদৌ কি, বা আমি অন্য একটি জি ++ বাগ আবিষ্কার করতে পারি?
- যদি এটি আইনী হয় তবে আমি কি কিছু বাজে ঝাঁকুনি ++ বাগ আবিষ্কার করেছি?
- বা আমি কি কেবল অনির্ধারিত আচরণের অন্ধকার পাতালখানায় ডুবেছি, তাই আমি নিজেই কেবল দোষী?
যে কোনও ইভেন্টে, আমি যদি এই খরগোশের গর্ত থেকে আমাকে বেরিয়ে আসতে সহায়তা করতে চাই, এমন কাউকে আমি আন্তরিকভাবে স্বাগত জানাব, যদি প্রয়োজন হয় তবে মাথা ব্যথার ব্যাখ্যা সরবরাহ করে। : ডি
next()
ফাংশনটির প্যারামিটার হিসাবে স্পষ্টভাবে একটি মনোোটোনিক ক্রমবর্ধমান সংখ্যা পাস করার প্রয়োজনীয়তা এড়াতে পারে , তবে আমি কীভাবে এটি কাজ করে তা সত্যই বুঝতে পারি না। যে কোনও ইভেন্টে, আমি আমার নিজের সমস্যার প্রতিক্রিয়া নিয়ে এখানে এসেছি: stackoverflow.com/a/60096865/566849