স্ট্যাটিক কনটেক্সপ্র্যাপ চর সম্পর্কে অপরিজ্ঞাত রেফারেন্স []


184

আমি static const charআমার ক্লাসে একটি অ্যারে রাখতে চাই জিসিসি অভিযোগ করেছে এবং আমাকে বলেছে আমার ব্যবহার করা উচিত constexpr, যদিও এখন এটি আমাকে বলেছে এটি একটি অপরিজ্ঞাত রেফারেন্স। যদি আমি অ্যারেটিকে সদস্যবিহীন করে তোলে তবে এটি সংকলন করে। কি হচ্ছে?

// .hpp
struct foo {
  void bar();
  static constexpr char baz[] = "quz";
};

// .cpp
void foo::bar() {
  std::string str(baz); // undefined reference to baz
}

1
কেবল একটি কুঁচক, এটি উদাহরণস্বরূপ বাজ যদি অন্তর্নিহিত হয়? তাহলে কি আপনি এটি অ্যাক্সেস করতে পারবেন? এটি একটি বাগও হতে পারে।
ব্যর্থদেব

1
@ পাব্বি: প্রশ্ন: কোন অনুবাদ ইউনিটে এটি সংজ্ঞায়িত করা হবে? উত্তর: শিরোনাম অন্তর্ভুক্ত সবকিছু। সমস্যা: একটি সংজ্ঞা বিধি লঙ্ঘন করে। ব্যতিক্রম: সংকলন-সময় ধ্রুবক ইন্টিগ্রালগুলি শিরোনামগুলিতে "আরম্ভ করা" যেতে পারে।
হাঁস Mooing

এটি int@ মুভিংডাক হিসাবে সূক্ষ্ম সংকলন করে এটি একটি অ-সদস্য হিসাবে সূক্ষ্মভাবে কাজ করে। এটাও কি নিয়ম লঙ্ঘন করবে না?
পাব্বি

@ পাব্বি 8: intএস ঠকাই। অ-সদস্য হিসাবে, এটি অনুমোদিত হবে না, যদি না সি ++ 11 (সম্ভাব্য) জন্য নিয়মগুলি পরিবর্তন করা হয়
মাকিং হাঁস

মতামত এবং upvotes বিবেচনা করে, এই প্রশ্নের আরও বিস্তারিত উত্তর প্রয়োজন, যা আমি নীচে যোগ করেছি।
শফিক ইয়াঘমোর

উত্তর:


187

আপনার সিপিপি ফাইল যুক্ত করুন:

constexpr char foo::baz[];

কারণ: আপনাকে ঘোষণার পাশাপাশি স্থির সদস্যের সংজ্ঞা দিতে হবে । ঘোষণা এবং আরম্ভকারী শ্রেণীর সংজ্ঞার ভিতরে চলে যায় তবে সদস্য সংজ্ঞা পৃথক হতে হয়।


70
এটি অদ্ভুত দেখাচ্ছে ... যেহেতু এটি এমন কিছু তথ্য সংকলক সরবরাহ করে বলে মনে হয় না যা আগে ছিল না ...
দ্রাক্ষালস

32
আপনার যখন ক্লাসের ঘোষণা .cpp ফাইলে থাকে তখন এটি আরও অদ্ভুত লাগে! আপনি ক্লাস ঘোষণায় ফিল্ডটি আরম্ভ করেন, তবে ক্লাসের নিচে কনটেক্সপ্রেপ চারু foo :: baz [] লিখে ফিল্ডটি আপনার এখনও " ঘোষণা " করতে হবে। দেখে মনে হচ্ছে যে কনস্টেক্সপ্র ব্যবহার করে প্রোগ্রামাররা একটি অদ্ভুত পরামর্শ অনুসরণ করে তাদের প্রোগ্রামগুলি সংকলন করতে পারে: এটিকে আবার ঘোষণা করুন।
লুকাশ কাজারভিনসকি

5
@ লুকাসজ সিজারউইনস্কি: আপনি যে শব্দটির সন্ধান করছেন তা "সংজ্ঞায়িত"।
কেরেক এসবি

5
ঠিক আছে, কোনও নতুন তথ্য নেই: ব্যবহার করুনdecltype(foo::baz) constexpr foo::baz;
এক-ব্যবহারকারী নয়

6
foo টেম্প্লাইটিজড হলে এক্সপ্রেশনটি কেমন হবে? ধন্যবাদ।
হেই

80

সি ++ 17 ইনলাইন ভেরিয়েবলগুলি উপস্থাপন করে

সি ++ 17 constexpr staticসদস্যের ভেরিয়েবলগুলির জন্য এই সমস্যাটি সমাধান করে যদি এটি অদ্ভুত-ব্যবহৃত হয় তবে লাইনটির বাইরে থাকা সংজ্ঞা প্রয়োজন। প্রাক-সি ++ 17 বিশদের জন্য এই উত্তরটির দ্বিতীয়ার্ধটি দেখুন।

প্রস্তাবনা P0386 ইনলাইন ভেরিয়েবল প্রয়োগ করার ক্ষমতা প্রবর্তন inlineসুনির্দিষ্টভাবে উল্লেখ করা ভেরিয়েবল করতে। বিশেষত এই ক্ষেত্রে স্ট্যাটিক সদস্য ভেরিয়েবলের জন্য constexprবোঝায় inline। প্রস্তাবে বলা হয়েছে:

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

এবং [বেসিক.ডিফ] পি 2 সংশোধিত:

একটি ঘোষণা একটি সংজ্ঞা হয় যদি না
...

  • এটি শ্রেণীর সংজ্ঞার বাইরে স্থিতিশীল ডেটা সদস্য হিসাবে ঘোষিত হয় এবং ভেরিয়েবলটি শ্রেণিবদ্ধের সাথে কনস্টেক্সপ্রাইফ স্পেসিফায়ার দিয়ে সংজ্ঞায়িত করা হয় (এই ব্যবহারটি অবচিত হয়; দেখুন [depr.static_constexpr]),

...

এবং [depr.static_constexpr] যুক্ত করুন :

পূর্ববর্তী সি ++ আন্তর্জাতিক স্ট্যান্ডার্ডগুলির সাথে সামঞ্জস্যের জন্য, একটি সংশ্লেষের স্থিতিশীল ডেটা সদস্যকে প্রাথমিকভাবে বিনা প্রাথমিকভাবে ক্লাসের বাইরে পুনরায় ঘোষিত করা যেতে পারে। এই ব্যবহার হ্রাস করা হয়। [উদাহরণ:

struct A {
  static constexpr int n = 5;  // definition (declaration in C++ 2014)
};

constexpr int A::n;  // redundant declaration (definition in C++ 2014)

 - শেষ উদাহরণ]


সি ++ 14 এবং তার আগেরটি

সি ++ ০৩ এ, কেবলমাত্র কনস্ট্যান্ট ইন্টিগ্রাল বা কনস্ট এনুমুরেশন ধরণের জন্য শ্রেণিক প্রারম্ভিক সরবরাহ করার অনুমতি দেওয়া হয়েছিল , সি ++ 11 এ এটি ব্যবহার করে আক্ষরিক ধরণেরconstexpr প্রসারিত করা হয়েছিল ।

সি ++ ১১-তে, কোনও স্থির constexprসদস্যের যদি এটি অদ্ভুত-ব্যবহৃত না হয় তবে আমাদের জন্য একটি নেমস্পেসের স্কোপ সংজ্ঞা সরবরাহ করার দরকার নেই , আমরা এটি খসড়া সি ++ 11 স্ট্যান্ডার্ড বিভাগ 9.4.2 [ক্লাস.স্ট্যাটিক.ডাটা] থেকে দেখতে পাচ্ছি যা বলেছে ( জোর আমার এগিয়ে যাচ্ছে ):

[...] আক্ষরিক ধরণের স্ট্যাটিক ডেটা সদস্যকে কনস্টেক্সপ্রাইফ স্পেসিফায়ার দিয়ে ক্লাস সংজ্ঞাতে ঘোষণা করা যেতে পারে; যদি তা হয় তবে এর ঘোষণাপত্রে একটি ব্রেস-বা-সমান-আরম্ভকারী নির্দিষ্ট করা হবে যাতে প্রতিটি প্রাথমিক-ক্লোজ যা একটি অ্যাসাইনমেন্ট-এক্সপ্রেশন থাকে একটি ধ্রুবক প্রকাশ। [দ্রষ্টব্য: এই উভয় ক্ষেত্রেই সদস্য স্থির মত প্রকাশের জন্য উপস্থিত হতে পারে। Noteend নোট] প্রোগ্রামটি যদি অদ্ভুতভাবে ব্যবহৃত হয় (3.2) প্রোগ্রামটিতে নাম তালিকাতে স্কোপে সংজ্ঞায়িত করা হবে এবং নেমস্পেস স্কোপ সংজ্ঞাটিতে কোনও আরম্ভকারী নেই contain

তাহলে প্রশ্নটি হয়ে ওঠে, এখানে কি baz অদ্ভুত ব্যবহার রয়েছে:

std::string str(baz); 

এবং উত্তর হ্যাঁ , এবং তাই আমাদের পাশাপাশি একটি নেমস্পেস স্কোপ সংজ্ঞাও প্রয়োজন।

সুতরাং আমরা কীভাবে নির্ধারণ করব যে কোনও ভেরিয়েবল অদ্ভুত-ব্যবহৃত হয় ? বিভাগে মূল সি ++ 11 3.2 শব্দকথা [বেসিক.ডেফ.অর্ডার] বলেছেন:

একটি এক্সপ্রেশনটি সম্ভাব্যভাবে মূল্যায়ন করা হয় যদি না এটি একটি মূল্যহীন অপরেনড (ক্লজ 5) বা এর একটি এক্সপ্রেশন হয়। একটি পরিবর্তনশীল যার নামটি সম্ভাব্য-মূল্যায়িত এক্সপ্রেশন হিসাবে উপস্থিত হয় অদ্ভুত-ব্যবহৃত হয় যদি না এটি এমন কোনও বস্তু হয় যা ধ্রুবক অভিব্যক্তিতে উপস্থিত হওয়ার জন্য প্রয়োজনীয়তাগুলি পূরণ করে (5.19) এবং লভ্যু-টু-রালভ্য রূপান্তর (4.1) অবিলম্বে প্রয়োগ করা হয়

সুতরাং bazএকটি ধ্রুবক অভিব্যক্তি পাওয়া যায় তবে অ্যালbaz হওয়ার কারণে প্রযোজ্য না হওয়ায় অবধি লভ্যালু-থেকে-রালভ রূপান্তরটি তত্ক্ষণাত্ প্রয়োগ করা হয় না । এটি বিভাগে 4.1 [আবশ্যক] আচ্ছাদিত রয়েছে যা বলে:

নন-ফাংশন, নন-অ্যারে টাইপ টি এর একটি আচ্ছাদন (৩.১০) একটি মূল্যে রূপান্তর করা যেতে পারে 3৫ [...]

অ্যারে-থেকে-পয়েন্টার রূপান্তরটিতে কী প্রয়োগ করা হয় ।

[বেসিক.ডেফ.অর্ডার] এর এই শব্দটির ত্রুটি প্রতিবেদন 712 এর কারণে পরিবর্তন করা হয়েছিল যেহেতু কিছু ক্ষেত্রে এই শব্দটির আওতাভুক্ত হয়নি তবে এই পরিবর্তনগুলি এই মামলার ফলাফলগুলিকে পরিবর্তন করে না।


সুতরাং আমরা কি পরিষ্কার করছি যে constexprএর সাথে কিছু করার নেই? ( bazযাইহোক যাইহোক একটি ধ্রুবক প্রকাশ)
এমএম

@ ম্যাটম্যাকনাব ভালভাবে কনসেক্সট্রপ প্রয়োজন যদি সদস্যটি না হয় integral or enumeration typeতবে অন্যথায়, হ্যাঁ, যা গুরুত্বপূর্ণ তা হল এটি একটি ধ্রুবক প্রকাশ
শফিক ইয়াঘমোর

প্রথম অনুচ্ছেদে "অর্ডার-ব্যবহৃত" "গন্ধযুক্ত-ব্যবহৃত" হিসাবে পড়া উচিত, আমি বিশ্বাস করি, তবে আমি সি ++ এর সাথে কখনই নিশ্চিত নই
এগার প্যাসকো

37

এটি সি ++ ১১-এ আসলেই একটি ত্রুটি - যেমন অন্যরা ব্যাখ্যা করেছেন, সি ++ ১১-তে স্থিতিশীল কনস্টেক্সপ্র সদস্য সদস্য ভেরিয়েবল, অন্য সমস্ত ধরণের কনস্টেক্সপ্রের বৈশ্বিক পরিবর্তনশীল এর বাহ্যিক সংযোগ রয়েছে, সুতরাং কোথাও স্পষ্টভাবে সংজ্ঞায়িত করতে হবে।

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

যদিও সুসংবাদ - এই ত্রুটিটি সি ++ 17 এ স্থির! পন্থাটি যদিও কিছুটা বিশৃঙ্খলাযুক্ত: সি ++ 17 এ, স্ট্যাটিক কনস্টেক্সারপ সদস্যের ভেরিয়েবলগুলি সুস্পষ্টভাবে ইনলাইন । রয়ে ইনলাইন ভেরিয়েবল প্রয়োগ সি ++ 17 একটি নতুন ধারণা, কিন্তু এটা কার্যকরভাবে তার মানে তারা একটি সুনির্দিষ্ট সংজ্ঞা যে কোন জায়গায় হবে না।


4
সি ++ 17 তথ্যের জন্য আপ। আপনি এই তথ্য গ্রহণযোগ্য উত্তরে যুক্ত করতে পারেন!
এসআর

5

আরও মার্জিত সমাধান কি এতে পরিবর্তিত হচ্ছে না char[]:

static constexpr char * baz = "quz";

এইভাবে আমাদের কোডের 1 লাইনে সংজ্ঞা / ঘোষণা / আরম্ভকারী থাকতে পারে।


9
সঙ্গে char[]আপনি ব্যবহার করতে পারেন sizeofকম্পাইল সময়ে স্ট্রিং এর দৈর্ঘ্য পেতে, সঙ্গে char *তুমি কি (এটা পয়েন্টার টাইপ, 1 প্রস্থ এই ক্ষেত্রে আসতে হবে) করতে পারেন।
gnzlbg

2
আপনি আইএসও সি ++ 11 এর সাথে কঠোর হতে চাইলে এটি সতর্কতাও উত্পন্ন করে।
শীতল শাহ

আমার উত্তরটি দেখুন যা sizeofইস্যুটি প্রদর্শন করে না এবং "কেবলমাত্র শিরোনাম" সমাধানগুলিতে ব্যবহার করা যেতে পারে
জোশ গ্রিফার

4

স্থিতিশীল সদস্যদের বাহ্যিক সংযোগের জন্য আমার কাজটি হল constexprরেফারেন্স সদস্য গেটারগুলি ব্যবহার করা (যা @ddebme থেকে উত্তরের মন্তব্য হিসাবে উত্থাপিত @gnzlbg সমস্যার মধ্যে পড়ে না)।
এই প্রবাদটি আমার কাছে গুরুত্বপূর্ণ কারণ আমি আমার প্রকল্পগুলিতে একাধিক .cpp ফাইল রাখাকে ঘৃণা করি এবং সংখ্যাটি একের মধ্যে সীমাবদ্ধ করার চেষ্টা করি, যা #includeএস এবং main()ফাংশন ব্যতীত কিছুই নয় nothing

// foo.hpp
struct foo {
  static constexpr auto& baz() { return "quz"; }
};

// some.cpp

  auto sz = sizeof(foo::baz()); // sz == 4

  auto& foo_baz = foo::baz();  // note auto& not auto
  auto sz2 =  sizeof(foo_baz);    // 4
  auto name = typeid(foo_baz).name();  // something like 'char const[4]'

-1

আমার পরিবেশে, জিসিসি ভেনশন 5.4.0। "-O2" যুক্ত করা এই সংকলন ত্রুটিটিকে ঠিক করতে পারে। মনে হয় জিসিসি অপ্টিমাইজেশনের জন্য জিজ্ঞাসা করলে এই কেসটি পরিচালনা করতে পারে।

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