সি ++ একটি টেম্পলেট শ্রেণিতে ক্লাসের বাইরে ক্লাসের 20 সংজ্ঞা


12

সি ++ এর 20 + স্ট্যান্ডার্ড অবধি, যখন আমরা কোনও ক্লাসের বাইরে থাকা অপারেটরটিকে সংজ্ঞায়িত করতে চেয়েছিলাম যা কোনও টেম্পলেট শ্রেণির কিছু ব্যক্তিগত সদস্য ব্যবহার করে, আমরা এর অনুরূপ একটি নির্মাণ ব্যবহার করব:

template <typename T>
class Foo;

template <typename T>
constexpr bool operator==(T lhs, const Foo<T>& rhs);

template <typename T>
class Foo {
public:
    constexpr Foo(T k) : mK(k) {}

    constexpr friend bool operator==<T>(T lhs, const Foo& rhs);

private:
    T mK;
};

template <typename T>
constexpr bool operator==(T lhs, const Foo<T>& rhs) {
    return lhs == rhs.mK;
}

int main() {
    return 1 == Foo<int>(1) ? 0 : 1;
}

যেহেতু সি ++ ২০, তবে আমরা ক্লাসের বাইরে থাকা ঘোষণাটি বাদ দিতে পারি, এইভাবে এগিয়ে ঘোষণাও যাতে আমরা ন্যায়সঙ্গতভাবে পালাতে পারি:

template <typename T>
class Foo {
public:
    constexpr Foo(T k) : mK(k) {}

    constexpr friend bool operator==<T>(T lhs, const Foo& rhs);
private:
    T mK;
};

template <typename T>
constexpr bool operator==(T lhs, const Foo<T>& rhs) {
    return lhs == rhs.mK;
}

Demo

এখন, আমার প্রশ্নটি হল, সি ++ এর কোন অংশটি আমাদের এটি করতে দেয়? এবং কেন আগে সি ++ স্ট্যান্ডার্ডে এটি সম্ভব ছিল না?


মন্তব্যে যেমন উল্লেখ করা হয়েছিল, ঝনক ডেমোতে উপস্থাপিত এই কোডটি গ্রহণ করে না, যা প্রস্তাব দেয় এটি প্রকৃতপক্ষে জিসিসিতে কোনও বাগ হতে পারে।

আমি জিসিসির বাগজিলায় একটি বাগ রিপোর্ট দায়ের করেছি


2
আমি ব্যক্তিগতভাবে ক্লাস সংজ্ঞা পছন্দ করি, টেম্পলেট ফাংশন (এবং ছাড় "ইস্যু" (এর সাথে কোনও মিল নেই "c string" == Foo<std::string>("foo")) এড়িয়ে ।
জারোড 42

@ জারোড 42 আমি পুরোপুরি একমত, আমিও শ্রেণিক সংজ্ঞা পছন্দ করি। আমি কেবল এটি অবাক করেই জানতে পেরেছিলাম যে C ++ 20 আমাদের ক্লাসের বাহ্যিকভাবে সংজ্ঞায়িত করার সময় ফাংশনটির স্বাক্ষরটি তিনবার পুনরাবৃত্তি না করার অনুমতি দেয়, এটি কোনও সর্বজনীন এপিআইতে কার্যকর হতে পারে যেখানে বাস্তবায়নটি একটি লুকানো .আইএনএল ফাইলটিতে রয়েছে।
প্রক্সিকটি

এটা আমি অসম্ভব বলে মনে করি না। আমি কীভাবে এটিকে এত সহজে সমস্যা ছাড়াই ব্যবহার করেছি?
ALX23z

1
হুম, এ temp.friend , অনেক পরিবর্তন, বিশেষ করে না 1.3 যা এই আচরণের জন্য দায়ী করা উচিত নয়। যেহেতু ঝনঝন আপনার কোডটি গ্রহণ করে না , তাই আমি বাগের সাথে জিসিসির দিকে ঝুঁকছি।
n314159

@ ALX23z ক্লাসটি শিষ্ট না হলে এটি ক্লাসের বাইরে ঘোষণা ছাড়াই কাজ করে।
প্রক্সিকটি

উত্তর:


2

জিসিসির একটি বাগ রয়েছে।

নাম অনুসন্ধানটি সর্বদা একটি এর আগে উপস্থিত টেমপ্লেটের নামগুলির জন্য সঞ্চালিত হয় <, এমনকি যখন প্রশ্নের মধ্যে নামটি কোনও নাম (বন্ধু, স্পষ্টতীকরণ, বা স্পষ্ট তাত্ক্ষণিক) ঘোষণার মধ্যে ঘোষণা করা হয়।

কারণ NAME operator==বন্ধু ঘোষণাপত্র একটি অযোগ্য নাম এবং একটি টেমপ্লেটে লুকআপ নাম সাপেক্ষে, দুই-ফেজ নাম লুকআপ নিয়ম প্রযোজ্য। এই প্রসঙ্গে, operator==কোনও নির্ভরশীল নাম নয় (এটি কোনও ফাংশন কলের অংশ নয়, সুতরাং এডিএল প্রযোজ্য নয়), তাই নামটি যেখানে দেখাবে সেখানে বাঁকানো হবে এবং আবদ্ধ হবে (দেখুন [টেম্প.নোডেপ] অনুচ্ছেদ 1)। আপনার উদাহরণটি দূষিত কারণ এই নামের অনুসন্ধানের কোনও ঘোষণা খুঁজে পাওয়া যায় না operator==

আমি প্রত্যাশা করব যে জিডিসি এটি P + 846R0 এর কারণে সি ++ 20 মোডে গ্রহণ করছে , যা operator==<T>(a, b)কোনও operator==টেমপ্লেট হিসাবে পূর্বের কোনও ঘোষণা দৃশ্যমান না থাকলেও কোনও টেমপ্লেটে ব্যবহারের অনুমতি দেয় (উদাহরণস্বরূপ) ।

এখানে আরও একটি আকর্ষণীয় টেস্টকেস রয়েছে:

template <typename T> struct Foo;

#ifdef WRONG_DECL
template <typename T> bool operator==(Foo<T> lhs, int); // #1
#endif

template <typename T> struct Foo {
  friend bool operator==<T>(Foo<T> lhs, float); // #2
};

template <typename T> bool operator==(Foo<T> lhs, float); // #3
Foo<int> f;

এর সাথে -DWRONG_DECL, জিসিসি এবং ক্লেং সম্মত হন যে এই প্রোগ্রামটি দুর্গঠিত: বন্ধুত্বের ঘোষণাপত্রের জন্য অযোগ্য যোগ্য অনুসন্ধান # 2, টেম্পলেট সংজ্ঞাটির প্রসঙ্গে, ঘোষণাকে # 1 খুঁজে পেয়েছে, যা তাত্ক্ষণিক বন্ধুর সাথে মেলে না Foo<int>। ঘোষণাপত্র # 3 এমনকি বিবেচনা করা হয় না, কারণ টেমপ্লেটে অযোগ্য তালিকাগুলি এটি খুঁজে পায় না।

এর সাথে -UWRONG_DECL, জিসিসি (সি ++ 17 এবং এর আগের) এবং ক্ল্যাং একমত যে এই প্রোগ্রামটি অন্য কোনও কারণে অ-গঠিত হয়েছে: operator==লাইন # 2 এ অযোগ্য অনুসন্ধানের জন্য কিছুই খুঁজে পায় না।

তবে এর সাথে -UWRONG_DECL, সি ++ ২০ মোডে জিসিসি সিদ্ধান্ত নিয়েছে যে এটি ঠিক আছে যে operator==# 2 এ অযোগ্য অনুসন্ধানের জন্য ব্যর্থ হয় (সম্ভবত P0846R0 এর কারণে), এবং তারপরে টেমপ্লেট ইনস্ট্যান্টেশন প্রসঙ্গটি থেকে অনুসন্ধানটি আবার পূর্বাবস্থায় ফিরে আসে, এখন # 3 খুঁজে পেয়েছে টেমপ্লেটগুলির জন্য সাধারণ দুই-পর্বের নাম দেখার নিয়ম লঙ্ঘন।


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