+ ব্যবহার করে একটি ল্যাম্বডায় ফাংশন পয়েন্টার এবং স্টেডি :: ফাংশনে অস্পষ্ট ওভারলোড সমাধান করা


94

নিম্নলিখিত কোডে, প্রথম কলটি fooঅস্পষ্ট, এবং তাই সংকলন করতে ব্যর্থ।

দ্বিতীয়, +ল্যাম্বডারের আগে যুক্ত হওয়ার সাথে, ফাংশন পয়েন্টার ওভারলোডের সমাধান করে।

#include <functional>

void foo(std::function<void()> f) { f(); }
void foo(void (*f)()) { f(); }

int main ()
{
    foo(  [](){} ); // ambiguous
    foo( +[](){} ); // not ambiguous (calls the function pointer overload)
}

কি +স্বরলিপি এখানে করছেন?

উত্তর:


100

+এক্সপ্রেশনে +[](){}ইউনারী হয় +অপারেটর। এটি [expr.unary.op] / 7 এ নিম্নলিখিত হিসাবে সংজ্ঞায়িত হয়েছে:

+অ্যানারি অপারেটরের অপারেন্ডে পাটিগণিত, আনস্কোপড গণনা, বা পয়েন্টার টাইপ থাকবে এবং ফলাফলটি আর্গুমেন্টের মান।

ল্যাম্বদা পাটিগণিত ধরণের ইত্যাদি নয়, তবে এটি রূপান্তরিত হতে পারে:

[expr.prim.lambda] / 3

ধরণ ল্যামডা প্রকাশ [...] একটি অনন্য, নামহীন অ ইউনিয়ন শ্রেণী প্রকার - নামক অবসান টাইপ - যার বৈশিষ্ট্য নিচে বর্ণনা করা হয়।

[expr.prim.lambda] / 6

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

অতএব, অ্যানারি +ফাংশন পয়েন্টার ধরণের রূপান্তরকে বাধ্য করে, যা এই ল্যাম্বদার জন্য void (*)()। সুতরাং, মত প্রকাশের ধরণটি +[](){}হ'ল এই ফাংশন পয়েন্টার প্রকার void (*)()

দ্বিতীয় ওভারলোড void foo(void (*f)())ওভারলোড রেজোলিউশনের জন্য র‌্যাঙ্কিংয়ের এক নির্ভুল ম্যাচে পরিণত হয় এবং তাই নির্বিঘ্নে বেছে নেওয়া হয় (প্রথম ওভারলোডটি কোনও সঠিক মিল নয়)।


ল্যাম্বডাকে অ-স্পষ্টত টেম্পলেট কর্টারের মাধ্যমে [](){}রূপান্তর করা যেতে পারে , যা কোনও ধরণের প্রয়োজন এবং প্রয়োজনীয়তা পূরণ করে takesstd::function<void()>std::functionCallableCopyConstructible

ল্যাম্বদাটি ক্লোজার ধরণেরvoid (*)() রূপান্তর ফাংশনের মাধ্যমেও রূপান্তরিত হতে পারে (উপরে দেখুন)।

উভয়ই ব্যবহারকারী-সংজ্ঞায়িত রূপান্তর ক্রম এবং একই র‌্যাঙ্কের। এজন্য অস্পষ্টতার কারণে প্রথম উদাহরণে ওভারলোড রেজোলিউশন ব্যর্থ হয় ।


ক্যাসিও নেেরির মতে, ড্যানিয়েল ক্রাগলারের একটি যুক্তির সমর্থিত, এই আনুষ্ঠানিক +কৌশলটি নির্দিষ্ট আচরণ হিসাবে চিহ্নিত করা উচিত, অর্থাৎ আপনি এটির উপর নির্ভর করতে পারেন (মন্তব্যগুলিতে আলোচনা দেখুন)।

তবুও, যদি আপনি অস্পষ্টতা এড়াতে চান তবে আমি ফাংশন পয়েন্টার ধরণের একটি স্পষ্ট কাস্ট ব্যবহার করার পরামর্শ দেব: আপনাকে কী করতে হবে এবং কেন এটি কাজ করে তা জিজ্ঞাসা করার দরকার নেই;)


4
@ ফ্রেড এএফাইক সদস্য ফাংশন পয়েন্টারগুলিকে অ-সদস্য ফাংশন পয়েন্টারে রূপান্তর করা যাবে না, একা ফাংশন লভ্যালু ছেড়ে দিন। আপনি std::bindকোনও std::functionঅবজেক্টের মাধ্যমে সদস্য ফাংশনকে বাঁধতে পারেন যা ফাংশন ল্যাভেলুতে অনুরূপ বলা যেতে পারে।
dyp

4
@ ডিআইপি: আমি বিশ্বাস করি আমরা কৌতূহলের উপর নির্ভর করতে পারি। প্রকৃতপক্ষে, ধরুন যে একটি বাস্তবায়ন operator +()একটি রাজ্যহীন বন্ধের ধরণের যোগ করে। অনুমান করুন যে এই অপারেটরটি ক্লোজার টাইপকে রূপান্তরিত করে এমন পয়েন্টার ব্যতীত অন্য কিছু দেয়। তারপরে, এটি এমন কোনও প্রোগ্রামের পর্যবেক্ষণযোগ্য আচরণকে পরিবর্তিত করবে যা 5.1.2 / 3 লঙ্ঘন করে। আপনি যদি এই যুক্তির সাথে একমত হন তবে দয়া করে আমাকে জানান।
ক্যাসিও নেরি

4
@ ক্যাসিওনেরি হ্যাঁ, এটি সেই জায়গা যেখানে আমি নিশ্চিত নই। আমি সম্মত হই যে একটি যুক্ত করার সময় পর্যবেক্ষণযোগ্য আচরণটি পরিবর্তিত হতে পারে operator +তবে এটি এমন পরিস্থিতির সাথে তুলনা করছে যা operator +শুরু করার মতো নেই। তবে এটি নির্দিষ্ট করা হয়নি যে বন্ধের ধরণের কোনও operator +ওভারলোড থাকবে না । "একটি বাস্তবায়ন নীচের বর্ণিত বর্ণনার চেয়ে ক্লোজারের ধরণকে আলাদাভাবে সংজ্ঞায়িত করতে পারে তবে শর্ত থাকে যে এটি [...] ব্যতীত অন্য কোন প্রোগ্রামের পর্যবেক্ষণযোগ্য আচরণকে পরিবর্তন করে না" তবে অপারেটর যুক্ত করা আইএমও ক্লোজারের ধরণটি কি থেকে আলাদা কিছুতে পরিবর্তন করে না "নীচে বর্ণিত"।
dyp

4
@ ডিআইপি: পরিস্থিতি যেখানে নেই সেখানে operator +()মানের দ্বারা বর্ণিত হ'ল। মান একটি প্রয়োগকরণকে নির্দিষ্ট করা থেকে আলাদা কিছু করার অনুমতি দেয়। উদাহরণস্বরূপ, যোগ করা হচ্ছে operator +()। তবে, যদি কোনও প্রোগ্রামের দ্বারা এই পার্থক্যটি পর্যবেক্ষণযোগ্য হয় তবে তা অবৈধ। একবার আমি কমপ্লেং.এল.সি.এল.কে জিজ্ঞাসা করলাম। সংশোধন করা হয়েছে যদি কোনও ক্লোজার টাইপ একটি টাইপডেফ যোগ করতে পারে result_typeএবং অন্যটি typedefsতাদের উপযুক্ত করে তোলে (উদাহরণস্বরূপ std::not1)। আমাকে বলা হয়েছিল যে এটি পর্যবেক্ষণযোগ্য হওয়ায় এটি পারেনি। আমি লিঙ্কটি সন্ধান করার চেষ্টা করব।
ক্যাসিও নেরি

6
ভিএস 15 আপনাকে এই মজাদার ত্রুটি দেয়: test.cpp (543): ত্রুটি C2593: 'অপারেটর +' দ্ব্যর্থক t \ test.cpp (543): নোট: 'বিল্ট-ইন সি ++ অপারেটর + (শূন্য (__cdecl *) (বাতিল )) 't \ test.cpp (543): নোট: বা' বিল্ট-ইন সি ++ অপারেটর + (শূন্য (__stdcall *) (শূন্য)) 't \ test.cpp (543): দ্রষ্টব্য: বা' বিল্ট-ইন সি ++ অপারেটর + (অকার্যকর (__फाস্টক্যাল *) (শূন্য)) 't \ টেস্ট কোডপিপি (543): দ্রষ্টব্য: বা' বিল্ট-ইন সি ++ অপারেটর + (শূন্য (__vectorcall *) (শূন্য)) 't \ test.cpp (543): নোট : যুক্তি তালিকার সাথে ম্যাচ করার চেষ্টা করার সময় '(wmain :: <lambda_d983319760d11be517b3d48b95b3fe58>) test.cpp (543): ত্রুটি C2088:' + ': শ্রেণীর জন্য অবৈধ
এড ল্যামবার্ট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.