কর্ট আম্মনের গৃহীত উত্তরটি ভাল তবে আমি মনে করি বাস্তবায়নের বিষয়ে আরও একটি গুরুত্বপূর্ণ বিষয় রয়েছে।
ধরুন আমার দুটি পৃথক অনুবাদ ইউনিট রয়েছে, "ওয়ান সিপিপি" এবং "two.cpp"।
struct A { int operator()(int x) const { return x+1; } };
auto b = [](int x) { return x+1; };
using A1 = A;
using B1 = decltype(b);
extern void foo(A1);
extern void foo(B1);
দুটি ওভারলোড foo
একই শনাক্তকারী ( foo
) ব্যবহার করে তবে বিভিন্ন ম্যাংলেড নাম রয়েছে। (পসিক্স-ইশ সিস্টেমে ব্যবহৃত ইটানিয়াম এবিআইতে, ম্যাঙ্গলেড নামগুলি রয়েছে _Z3foo1A
এবং এই বিশেষ ক্ষেত্রে, _Z3fooN1bMUliE_E
))
struct A { int operator()(int x) const { return x + 1; } };
auto b = [](int x) { return x + 1; };
using A2 = A;
using B2 = decltype(b);
void foo(A2) {}
void foo(B2) {}
সি ++ সংকলককে অবশ্যই নিশ্চিত করতে হবে যে void foo(A1)
"two.cpp" এ থাকা ম্যাংলেড নামটি extern void foo(A2)
"ওয়ান সিপিপি" এর ম্যাংলেড নামের মতো , যাতে আমরা দুটি অবজেক্ট ফাইলকে একসাথে যুক্ত করতে পারি। এটি দুটি ধরণের "একই ধরণের" হওয়ার শারীরিক অর্থ : এটি মূলত পৃথকভাবে সংকলিত অবজেক্ট ফাইলগুলির মধ্যে এবিআই-সামঞ্জস্যতা সম্পর্কে।
সি ++ সংকলকটি এটির প্রয়োজন হয় নাB1
এবং B2
এটি "একই ধরণের" ensure (আসলে, এগুলি নিশ্চিত করা দরকার যে তারা বিভিন্ন ধরণের; তবে এটি এখনকার মতো গুরুত্বপূর্ণ নয়))
সংকলক A1
এবং A2
এটি "একই ধরণের" তা নিশ্চিত করতে কোন শারীরিক প্রক্রিয়া ব্যবহার করে ?
এটি কেবল টাইপিডেফগুলির মধ্য দিয়ে যায় এবং তারপরে প্রকারটির সম্পূর্ণরূপে যোগ্যতাসম্পন্ন নামটি দেখায়। এটি একটি শ্রেণীর নামযুক্ত A
। (ঠিক আছে, ::A
যেহেতু এটি বিশ্বব্যাপী নেমস্পেসে রয়েছে)) সুতরাং এটি উভয় ক্ষেত্রেই একই রকম। এটা বুঝতে সহজ। আরও গুরুত্বপূর্ণ, এটি কার্যকর করা সহজ । যদি দুটি শ্রেণী ধরনের একই ধরনের হয় দেখার জন্য, আপনাকে তাদের নাম গ্রহণ করা এবং একটি strcmp
। কোনও ফাংশনের মাংডেল নামের একটি শ্রেণির ধরণটি ছড়িয়ে দেওয়ার জন্য, আপনি তার নামে অক্ষরের সংখ্যা লিখুন, তারপরে সেই অক্ষরগুলি অনুসরণ করুন।
সুতরাং, নামযুক্ত প্রকারগুলি ম্যাঙ্গেল করা সহজ।
কি শারীরিক প্রক্রিয়া পারে তা নিশ্চিত কম্পাইলার ব্যবহার B1
এবং B2
"একই ধরনের," একটি প্রকল্পিত দুনিয়া আছে যেখানে সি ++ তাদের প্রয়োজনীয় একই ধরনের হতে হবে?
ওয়েল, এটা ধরনের নাম ব্যবহার করতে পারে না কারণ টাইপ না আছে একটি নাম।
হতে পারে এটি কোনওভাবে ল্যাম্বদার দেহের পাঠ্যটি এনকোড করতে পারে । তবে এটি এক ধরনের বিশ্রী হবে, কারণ আসলে b
"ওয়ান.সি.পি.পি." এর b
মধ্যে "two.cpp": "ওয়ান.সি.পি." আছে x+1
এবং "two.cpp" আছে তার থেকে সূক্ষ্মভাবে আলাদা x + 1
। সুতরাং আমাদের এমন একটি নিয়ম নিয়ে আসতে হবে যাতে বলা হয় যে এই শ্বেত স্পেসের পার্থক্য কোনও বিষয় নয়, বা এটি করে (সর্বোপরি তাদেরকে বিভিন্ন ধরণের করে তোলে), বা সম্ভবত এটি করে (সম্ভবত প্রোগ্রামটির বৈধতা বাস্তবায়ন-সংজ্ঞায়িত , বা হতে পারে এটি "রোগ নির্ধারিত কোনও ডায়াগনস্টিকের প্রয়োজন নেই")। যাইহোক,A
অসুবিধা থেকে মুক্তির সহজতম উপায়টি হ'ল প্রতিটি ল্যাম্বডা এক্সপ্রেশন একটি অনন্য ধরণের মান তৈরি করে। তারপর বিভিন্ন অনুবাদ ইউনিটে সংজ্ঞায়িত দুটি ল্যাম্বদা প্রকারগুলি অবশ্যই একই ধরণের নয় । একটি একক অনুবাদ ইউনিটের মধ্যে, আমরা উত্স কোডের শুরু থেকে কেবল গণনা করে ল্যাম্বদা প্রকারগুলিকে "নাম" দিতে পারি:
auto a = [](){};
auto b = [](){};
auto f(int x) {
return [x](int y) { return x+y; };
}
auto g(float x) {
return [x](int y) { return x+y; };
}
অবশ্যই এই নামের অর্থ কেবল এই অনুবাদ ইউনিটের মধ্যে রয়েছে। এই টিইউ $_0
সবসময় অন্য কোনও টিইউর থেকে সবসময় আলাদা ধরণের থাকে $_0
যদিও এই টিইউ struct A
সবসময় অন্য কোনও টিইউর মতো একই ধরণের struct A
।
যাইহোক, লক্ষ্য করুন যে আমাদের "ল্যাম্বডাটির পাঠ্যটি এনকোড করুন" ধারণার মধ্যে আরও একটি সূক্ষ্ম সমস্যা ছিল: ল্যাম্বডাস $_2
এবং $_3
ঠিক একই পাঠ্যটি নিয়ে গঠিত , তবে তাদের স্পষ্টতই একই ধরণের হিসাবে বিবেচনা করা উচিত নয় !
যাইহোক, সি ++ এর মতো একটি স্বেচ্ছাসেবী সি ++ এক্সপ্রেশনটির পাঠ্যকে কীভাবে আঁকতে হয় তা জানতে সংকলকটির প্রয়োজন হয়
template<class T> void foo(decltype(T())) {}
template void foo<int>(int);
কিন্তু সি ++ (এখনও) কোনও স্বেচ্ছাসেবী সি ++ বিবৃতি ম্যাঙ্গেল করতে হবে তা জানতে সংকলকটির প্রয়োজন নেই । decltype([](){ ...arbitrary statements... })
এমনকি সি ++ ২০ তেও দুর্গঠিত।
এছাড়াও নোটিশ যে এটা সহজ দিতে একটি নামহীন টাইপ ব্যবহার করার একটি স্থানীয় ওরফে typedef
/ using
। আমার অনুভূতি আছে যে আপনার প্রশ্নটি এমন কিছু করার চেষ্টা করে উত্থাপিত হয়েছিল যা এরকমভাবে সমাধান হতে পারে।
auto f(int x) {
return [x](int y) { return x+y; };
}
using AdderLambda = decltype(f(0));
int of_one(AdderLambda g) { return g(1); }
int main() {
auto f1 = f(1);
assert(of_one(f1) == 2);
auto f42 = f(42);
assert(of_one(f42) == 43);
}
সংযোজন সম্পাদনা করুন: অন্যান্য উত্তরের উপর আপনার কিছু মন্তব্য পড়ে, মনে হচ্ছে আপনি কেন ভাবছেন
int add1(int x) { return x + 1; }
int add2(int x) { return x + 2; }
static_assert(std::is_same_v<decltype(add1), decltype(add2)>);
auto add3 = [](int x) { return x + 3; };
auto add4 = [](int x) { return x + 4; };
static_assert(not std::is_same_v<decltype(add3), decltype(add4)>);
এটি কারণ ক্যাপচারহীন ল্যাম্বডাসগুলি ডিফল্ট-গঠনমূলক ti (সি ++ তে কেবল সি ++ 20 হিসাবে রয়েছে তবে এটি সর্বদা ধারণাগতভাবে সত্য)
template<class T>
int default_construct_and_call(int x) {
T t;
return t(x);
}
assert(default_construct_and_call<decltype(add3)>(42) == 45);
assert(default_construct_and_call<decltype(add4)>(42) == 46);
আপনি চেষ্টা যদি default_construct_and_call<decltype(&add1)>
, t
একটি ডিফল্ট-সক্রিয়া ফাংশন পয়েন্টার হবে এবং আপনি সম্ভবত segfault চাই। এটি, মত, দরকারী নয়।