মান সূচনাতে আমার প্রয়াসটি একটি ফাংশন ঘোষণা হিসাবে ব্যাখ্যা করা হয় এবং কেন এ (()) হয় না; ইহা সমাধান করো?


158

স্ট্যাক ওভারফ্লো আমাকে শিখিয়েছে এমন অনেকগুলি বিষয়গুলির মধ্যে যা "সবচেয়ে ভেক্সিং পার্স" হিসাবে পরিচিত, যা শ্রেণিবদ্ধভাবে একটি লাইনের সাহায্যে প্রদর্শিত হয়

A a(B()); //declares a function

যদিও এটি বেশিরভাগ ক্ষেত্রে, স্বজ্ঞাতভাবে কোনও aধরণের অবজেক্টের ঘোষণা হিসাবে উপস্থিত হয় A, একটি অস্থায়ী Bবস্তুকে কনস্ট্রাক্টর প্যারামিটার হিসাবে গ্রহণ করে , এটি আসলে কোনও ফাংশনকে একটি aফিরিয়ে আনার ঘোষণা দেয়, কোনও ফাংশনে Aএকটি পয়েন্টার গ্রহণ করে যা ফিরে আসে Bএবং নিজেই কোনও পরামিতি নেয় না । একইভাবে লাইন

A a(); //declares a function

এছাড়াও একই বিভাগের অধীনে আসে, যেহেতু কোনও বস্তুর পরিবর্তে এটি একটি ফাংশন ঘোষণা করে। এখন, প্রথম ক্ষেত্রে, এই ইস্যুটির স্বাভাবিক কাজটি হ'ল চারপাশে বন্ধনী / বন্ধনীগুলির একটি অতিরিক্ত সেট যুক্ত করা B(), কারণ সংকলকটি তখন এটি কোনও বস্তুর ঘোষণার হিসাবে ব্যাখ্যা করবে as

A a((B())); //declares an object

তবে, দ্বিতীয় ক্ষেত্রে, একই কাজটি একটি সংকলন ত্রুটির দিকে পরিচালিত করে

A a(()); //compile error

আমার প্রশ্ন, কেন? হ্যাঁ আমি খুব ভালভাবে অবগত যে সঠিক 'ওয়ার্কআরন্ড' এটিতে পরিবর্তন করা হয়েছে A a;, তবে আমি জানতে আগ্রহী যে এটি ()প্রথমটি উদাহরণে সংকলকটির জন্য অতিরিক্ত কী করে যা এটি পুনরায় প্রয়োগ করার সময় কাজ করে না দ্বিতীয় উদাহরণ। A a((B()));কাজটি কি আদর্শের ক্ষেত্রে নির্দিষ্ট ব্যতিক্রম?


20
(B())এটি কেবলমাত্র একটি সি ++ এক্সপ্রেশন, এর চেয়ে বেশি কিছুই নয়। এটি কোনও ধরণের ব্যতিক্রম নয়। এটি কেবলমাত্র পার্থক্যটি হ'ল এটি সম্ভবত কোনও ধরণের হিসাবে পার্স করার কোনও উপায় নেই এবং তাই এটি নয়।
পাভেল মিনায়েভ

12
এছাড়া উল্লেখ করা উচিত যে দ্বিতীয় ক্ষেত্রে, A a();হয় না একই বিষয়শ্রেণীতে। জন্য কম্পাইলার , এটা বিশ্লেষণ করতে কোনো অন্যভাবে না হয়: যে স্থানে একটি সূচনাকারী না, খালি প্রথম বন্ধনী নিয়ে গঠিত তাই এই সর্বদা একটি ফাংশন ঘোষণা।
জোহানেস স্কাউব -

11
লিটব এর দুর্দান্ত পয়েন্টটি একটি সূক্ষ্ম তবুও গুরুত্বপূর্ণ এবং এটি জোর দেওয়ার মতো - এই ঘোষণায় 'এ' (বি ()) 'দ্বিপাক্ষিকতা' বি () 'র বিশ্লেষণে থাকার কারণে -> এটি উভয়ই একটি অভিব্যক্তি এবং হতে পারে একটি ঘোষণা এবং সংকলক অবশ্যই এক্সপ্রেসের তুলনায় ডিক্সেল বাছাই করতে পারে - সুতরাং যদি বি () ডেসল হয় তবে 'এ' কেবল একটি ফানক ডেল (কোনও পরিবর্তনশীল ডেস্ক নয়) হতে পারে। যদি '(ক)' কে প্রাথমিক স্তরের অনুমতি দেওয়া হয় তবে 'এ ক ()' দ্ব্যর্থক হবে - তবে এটি এক্সপ্রেস বনাম ডেসেল নয়, তবে ভের ডেসাল বনাম ফানক ডেসেল - কোনও ডেলকে অন্যের চেয়ে বেশি পছন্দ করার কোনও নিয়ম নেই - এবং তাই '() এখানে কেবলমাত্র আরম্ভকারী হিসাবে অনুমোদিত নয় - এবং অস্পষ্টতা বৃদ্ধি পায় না।
ফয়সাল ভালি

6
A a();হয় না একটি উদাহরণ সবচেয়ে অসন্তোষজনক পার্স । এটি কেবল একটি ফাংশন ঘোষণা, ঠিক যেমন সি তে রয়েছে
পিট বেকার

2
"সঠিক 'workaround' এটিকে পরিবর্তন করা A a;" ভুল। এটি আপনাকে একটি পিওডি ধরণের সূচনা দেবে না। অন্তর্মুখী লেখার জন্য A a{};
চিয়ার্স এবং এইচটিএইচ - আলফ

উত্তর:


70

কোনও আলোকিত উত্তর নেই, এটি কেবল কারণ এটি সি ++ ভাষা দ্বারা বৈধ বাক্য গঠন হিসাবে সংজ্ঞায়িত করা হয়নি ... সুতরাং ভাষাটির সংজ্ঞা অনুসারে এটি তাই।

যদি আপনার মধ্যে কোনও ভাব থাকে তবে তা বৈধ valid উদাহরণ স্বরূপ:

 ((0));//compiles

এমনকি সহজ কথায় বলা যায় : কারণ (x)এটি একটি বৈধ সি ++ এক্সপ্রেশন, যদিও ()নেই।

ভাষা কীভাবে সংজ্ঞায়িত করা হয়, এবং সংকলকরা কীভাবে কাজ করে সে সম্পর্কে আরও জানতে আপনার ফর্মাল ভাষা তত্ত্ব বা আরও নির্দিষ্টভাবে কনটেক্সট ফ্রি গ্রামারস (সিএফজি) এবং সীমাবদ্ধ রাষ্ট্র মেশিনের মতো সম্পর্কিত উপাদান সম্পর্কে শিখতে হবে । উইকিপিডিয়া পৃষ্ঠাগুলি পর্যাপ্ত পরিমাণে না হলেও আপনি যদি এতে আগ্রহী হন তবে আপনাকে একটি বই পেতে হবে।


45
এমনকি সহজ কথায় বলা যায় : কারণ (x)এটি একটি বৈধ সি ++ এক্সপ্রেশন, যদিও ()নেই।
পাভেল মিনায়েভ

আমি এই উত্তরটি গ্রহণ করেছি, এছাড়াও আমার প্রাথমিক প্রশ্নে পাভেলের মন্তব্য আমাকে অনেক সাহায্য করেছে
জিআরবি


29

সি ফাংশন ঘোষক

প্রথমত, সি ইন সি রয়েছে, A a()ফাংশন ডিক্লেয়ারেশন। উদাহরণস্বরূপ, putcharনিম্নলিখিত ঘোষণা আছে। সাধারণত, এই জাতীয় ঘোষণাগুলি শিরোনাম ফাইলগুলিতে সংরক্ষণ করা হয়, তবে কোনও কাজই আপনাকে ম্যানুয়ালি লিখতে বাধা দেয় না, যদি আপনি জানেন যে ফাংশনটির ঘোষণাপত্রটি কেমন দেখাচ্ছে। আর্গুমেন্টের নামগুলি ঘোষণায় alচ্ছিক, তাই আমি এই উদাহরণে এটি বাদ দিয়েছি।

int putchar(int);

এটি আপনাকে এই জাতীয় কোড লিখতে দেয়।

int puts(const char *);
int main() {
    puts("Hello, world!");
}

সি আপনাকে ফাংশন কলের মতো দেখতে দুর্দান্ত পঠনযোগ্য সিনট্যাক্স সহ ফাংশনগুলি যুক্তি হিসাবে হিসাবে ফাংশনগুলি সংজ্ঞায়িত করতে দেয় (ভাল, এটি পঠনযোগ্য, যতক্ষণ আপনি ফাংশনে কোনও পয়েন্টার ফিরিয়ে দেবেন না)।

#include <stdio.h>

int eighty_four() {
    return 84;
}

int output_result(int callback()) {
    printf("Returned: %d\n", callback());
    return 0;
}

int main() {
    return output_result(eighty_four);
}

যেমনটি আমি উল্লেখ করেছি, সি হেডার ফাইলগুলিতে যুক্তির নাম বাদ দেওয়ার অনুমতি দেয়, সুতরাং output_resultহেডার ফাইলটিতে এটির মতো দেখাবে।

int output_result(int());

কনস্ট্রাক্টরে একটি যুক্তি

তুমি কি তাকে চিনতে পারো না? ঠিক আছে, আমি আপনাকে স্মরণ করিয়ে দিন।

A a(B());

হ্যাঁ, এটি ঠিক একই ফাংশন ঘোষণা। Aহয় int, aহয় output_resultএবং Bহয়int

আপনি সহজেই সি ++ এর নতুন বৈশিষ্ট্যগুলির সাথে সি এর একটি বিরোধ লক্ষ্য করতে পারেন। নির্ভুলভাবে বলতে গেলে, নির্মাতারা শ্রেণীর নাম এবং প্রথম বন্ধনী এবং ()পরিবর্তে পরিবর্তিত ডিক্লেয়ারেশন সিনট্যাক্স =। ডিজাইনের মাধ্যমে, সি ++ সি কোডের সাথে সামঞ্জস্যপূর্ণ হওয়ার চেষ্টা করে, এবং তাই এটি এই ক্ষেত্রে মোকাবেলা করতে হবে - এমনকি বাস্তবে কেউ পাত্তা না দিলেও। অতএব, পুরানো সি বৈশিষ্ট্যগুলির নতুন সি ++ বৈশিষ্ট্যগুলির চেয়ে অগ্রাধিকার রয়েছে। ঘোষণার ব্যাকরণটি নতুন সিনট্যাক্সের সাথে প্রত্যাবর্তনের আগে, নামটিকে ফাংশন হিসাবে মিলানোর চেষ্টা করে() ব্যর্থ হলে এটির ।

যদি এই বৈশিষ্ট্যগুলির মধ্যে একটির অস্তিত্ব না থাকে বা অন্যরকম সিনট্যাক্স থাকে (যেমন {} সি ++ 11 এর মতো), তবে এই সমস্যাটি একটি যুক্তির মাধ্যমে সিনট্যাক্সের জন্য কখনও ঘটেনি।

এখন আপনি জিজ্ঞাসা করতে পারেন কেন A a((B()))কাজ করে। ঠিক আছে, আসুন output_resultঅকেজো বন্ধনী যুক্ত করুন।

int output_result((int()));

এটি কাজ করবে না। ব্যাকরণটি বন্ধনীতে না থাকার জন্য পরিবর্তনশীল প্রয়োজন।

<stdin>:1:19: error: expected declaration specifiers or ‘...’ before ‘(’ token

তবে সি ++ এখানে স্ট্যান্ডার্ড এক্সপ্রেশন আশা করে। সি ++ এ আপনি নিম্নলিখিত কোডটি লিখতে পারেন।

int value = int();

এবং নিম্নলিখিত কোড।

int value = ((((int()))));

সি ++ প্রত্যাশা প্রত্নতুলীর অভ্যন্তরের অভ্যন্তরের ভিতরে ... ভাল ... এক্সপ্রেশনটি সি প্রকারের বিপরীতে যেমন প্রত্যাশা করে। প্যারেন্টিসিস এখানে কিছু বোঝায় না। যাইহোক, অকেজো বন্ধনী tingোকানোর মাধ্যমে, সি ফাংশন ঘোষণাটি মিলছে না এবং নতুন সিনট্যাক্সটি সঠিকভাবে মিলে যেতে পারে (যা কেবল কোনও এক্সপ্রেশন যেমন প্রত্যাশা করে যেমন2 + 2 )।

কনস্ট্রাক্টরে আরও যুক্তি

অবশ্যই একটি যুক্তি চমৎকার, কিন্তু দুটি সম্পর্কে কি? এটি এমন নয় যে নির্মাণকারীদের কেবল একটি যুক্তি থাকতে পারে। অন্তর্নির্মিত ক্লাসগুলির মধ্যে একটি যা দুটি তর্ক করেstd::string

std::string hundred_dots(100, '.');

এটি সমস্ত ভাল এবং সূক্ষ্ম (প্রযুক্তিগতভাবে, এটি সবচেয়ে ভেক্সিং পার্স হতে পারে যদি এটি হিসাবে লেখা হয় std::string wat(int(), char())তবে আসুন সত্যবাদী হন - কে তা লিখবে? তবে এই কোডটির একটি ভেক্সিং সমস্যা আছে বলে ধরে নেওয়া যাক আপনি ধরে নিতেই হবে প্রথম বন্ধনীতে।

std::string hundred_dots((100, '.'));

বেশ তাই না।

<stdin>:2:36: error: invalid conversion from char to const char*’ [-fpermissive]
In file included from /usr/include/c++/4.8/string:53:0,
                 from <stdin>:1:
/usr/include/c++/4.8/bits/basic_string.tcc:212:5: error:   initializing argument 1 of std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’ [-fpermissive]
     basic_string<_CharT, _Traits, _Alloc>::
     ^

আমি নিশ্চিত নই কেন জি ++ রূপান্তর charকরার চেষ্টা করে const char *। যে কোনও উপায়ে, কনস্ট্রাক্টরকে টাইপের মাত্র একটি মান দিয়ে ডাকা হত char। কোনও ওভারলোড নেই যার এক প্রকারের যুক্তি রয়েছে char, তাই সংকলক বিভ্রান্ত। আপনি জিজ্ঞাসা করতে পারেন - আর্গুমেন্টটি টাইপের চরের কেন?

(100, '.')

হ্যাঁ, , এখানে একটি কমা অপারেটর। কমা অপারেটর দুটি আর্গুমেন্ট নেয় এবং ডান দিকের যুক্তি দেয়। এটি সত্যিই দরকারী নয়, তবে এটি আমার ব্যাখ্যাটির জন্য পরিচিত to

পরিবর্তে, সর্বাধিক ভেক্সিং পার্স সমাধান করার জন্য, নিম্নলিখিত কোডটি প্রয়োজন।

std::string hundred_dots((100), ('.'));

আর্গুমেন্টগুলি প্রথম অভিব্যক্তি নয়, বন্ধনীতে রয়েছে। প্রকৃতপক্ষে, কেবলমাত্র একটির এক্সপ্রেশনগুলির বন্ধনীতে থাকা দরকার, কারণ এটি সি ++ বৈশিষ্ট্যটি ব্যবহার করতে সি ব্যাকরণ থেকে সামান্য বিরতিই যথেষ্ট। বিষয়গুলি আমাদের শূন্য আর্গুমেন্টের পর্যায়ে নিয়ে আসে।

কনস্ট্রাক্টরে জিরো আর্গুমেন্ট

eighty_fourআমার ব্যাখ্যাতে আপনি হয়ত ফাংশনটি লক্ষ্য করেছেন ।

int eighty_four();

হ্যাঁ, এটি সবচেয়ে ভেক্সিং পার্স দ্বারাও প্রভাবিত হয়। এটি একটি বৈধ সংজ্ঞা এবং আপনি সম্ভবত শিরোনাম ফাইলগুলি তৈরি করেছেন (এবং আপনার হওয়া উচিত) one বন্ধনী যুক্ত করা এটি ঠিক করে না।

int eighty_four(());

কেন যে এত? ভাল, ()একটি অভিব্যক্তি নয়। সি ++ এ আপনাকে প্রথম বন্ধনীগুলির মধ্যে প্রকাশ করতে হবে। আপনি auto value = ()সি ++ এ লিখতে পারবেন না , কারণ এর ()অর্থ কিছু নেই (এবং খালি টিপলের মতো হলেও (পাইথন দেখুন) এটি একটি যুক্তি হবে, শূন্য নয়)। কার্যত তার মানে আপনি সি ++ 11 এর {}সিনট্যাক্স ব্যবহার না করে শর্টহ্যান্ড সিনট্যাক্স ব্যবহার করতে পারবেন না , কারণ বন্ধনীতে কোনও মত প্রকাশ নেই এবং ফাংশন ঘোষণার জন্য সি ব্যাকরণ সর্বদা প্রযোজ্য হবে।


12

আপনি পরিবর্তে পারে

A a(());

ব্যবহার

A a=A();

32
'ভাল workaround' সমতুল্য নয়। 0 দিয়ে int a = int();আরম্ভ aকরে, অচিরাচরিত int a;পাতা ছেড়ে দেয় a। একটি সঠিক কর্মসংস্থান হ'ল A a = {};সমষ্টিগুলির জন্য ব্যবহার করা, A a;যখন ডিফল্ট-আরম্ভকরণ আপনি যা চান তা করেন এবং A a = A();অন্যান্য সমস্ত ক্ষেত্রে - বা কেবল A a = A();ধারাবাহিকভাবে ব্যবহার করুন । সি ++ 11 এ, কেবল ব্যবহার করুনA a {};
রিচার্ড স্মিথ

6

আপনার উদাহরণের অন্তর্নিহিত প্যারেনগুলি একটি অভিব্যক্তি হবে, এবং সি ++ এ ব্যাকরণটি একটির সাথে অন্যরকম বা কমা এবং অন্য একটি expressionহিসাবে সংজ্ঞায়িত হয়েছে (পরিশিষ্ট A.4 - ব্যাকরণের সংক্ষিপ্তসার / এক্সপ্রেশন)।assignment-expressionexpressionassignment-expression

ব্যাকরণ আরও একটি সংজ্ঞায়িত assignment-expression বিভিন্ন ধরণের অভিব্যক্তিগুলির মধ্যে হিসাবে একটিকে করে, যার কোনোটাই কিছুই (বা কেবল সাদা অংশ) হতে পারে না।

সুতরাং আপনি যা করতে পারবেন না তার A a(())কারণ ব্যাকরণ এটির অনুমতি দেয় না। তবে, আমি উত্তর দিতে পারছি না যে লোকেরা সি ++ তৈরি করেছে তারা খালি প্যারেনগুলির এই বিশেষ ব্যবহারকে কোনও বিশেষ ক্ষেত্রে হিসাবে অনুমতি দেয় না - আমি অনুমান করতে পারি যে যদি তারা সেখানে থাকে তবে তারা এই জাতীয় বিশেষ ক্ষেত্রে রাখতেন না if একটি যুক্তিসঙ্গত বিকল্প।

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