কোনও ফাংশনের অভ্যন্তরে স্থির কনস্টেক্সপ্র ভেরিয়েবলটি কী বোঝায়?


192

যদি কোনও ফাংশনের ভিতরে আমার ভেরিয়েবল থাকে (বলুন, একটি বড় অ্যারে), তবে এটি উভয়ই staticএবং এটি ঘোষণার অর্থ constexprকি? constexprগ্যারান্টি দেয় যে সংকলন সময়ে অ্যারে তৈরি হয়েছে, তাই কি staticঅকেজো হবে?

void f() {
    static constexpr int x [] = {
        // a few thousand elements
    };
    // do something with the array
}

কি staticকোডটি বা শব্দার্থবিদ্যা পরিপ্রেক্ষিতে আসলে করছেন কিছু আছে?

উত্তর:


230

সংক্ষিপ্ত উত্তরটি কেবল কার্যকর নয় static, এটি সর্বদা পছন্দসই হবে।

প্রথমে এটি দ্রষ্টব্য staticএবং constexprএকে অপরের থেকে সম্পূর্ণ স্বাধীন। staticমৃত্যুর সময় বস্তুর আজীবন সংজ্ঞা দেয়; constexprসংকলনের সময় অবজেক্টটি উপলভ্য হওয়া উচিত তা নির্দিষ্ট করে। সংকলন এবং সম্পাদন হ'ল সময় এবং স্থান উভয় ক্ষেত্রেই বিরক্তি এবং বিচ্ছিন্ন। সুতরাং প্রোগ্রামটি সংকলিত হয়ে গেলে constexprআর প্রাসঙ্গিক হয় না।

ঘোষিত প্রতিটি পরিবর্তনশীল constexprসুস্পষ্টভাবে constতবে constএবং staticপ্রায় অরথগোনাল ( static constপূর্ণসংখ্যার সাথে মিথস্ক্রিয়া ব্যতীত ) are

C++অবজেক্ট মডেল (§1.9) যে সব অন্যান্য তুলনায় বিট-ক্ষেত্র মেমরি অন্তত একটি বাইট ব্যাপৃত এবং ঠিকানা রয়েছে বস্তু প্রয়োজন; তদুপরি একটি নির্দিষ্ট মুহুর্তে একটি প্রোগ্রামে পর্যবেক্ষণযোগ্য এই জাতীয় সমস্ত বস্তুর অবশ্যই আলাদা ঠিকানা থাকতে হবে (অনুচ্ছেদ 6)। স্থানীয় কম-স্ট্যাটিক কনস্ট অ্যারের সাথে ফাংশনটির প্রতিটি অনুরোধের জন্য স্ট্যাকের জন্য একটি নতুন অ্যারে তৈরি করার জন্য এটি সংকলকটির পুরোপুরি প্রয়োজন হয় না, কারণ সংকলক as-ifনীতিতে আশ্রয় নিতে পারে তবে শর্ত থাকে যে এটি প্রমাণ করতে পারে যে এই জাতীয় অন্য কোনও জিনিস হতে পারে না পালিত।

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

অন্যদিকে, একটি স্থানীয় static constঅবজেক্ট সমস্ত পর্যবেক্ষক দ্বারা ভাগ করা হয় এবং তদ্ব্যতীত এটির সংজ্ঞা দেওয়া ফাংশনটি কখনও না বলা হলেও এটি আরম্ভ করা যেতে পারে। সুতরাং উপরেরগুলির কোনওটি প্রযোজ্য নয়, এবং একটি সংকলক কেবল এটির একটি একক উদাহরণ উত্পন্ন করতে বিনামূল্যে নয়; এটি কেবলমাত্র পঠনযোগ্য স্টোরেজে এটির একক উদাহরণ উত্পন্ন করতে পারে।

সুতরাং আপনি অবশ্যই static constexprআপনার উদাহরণ ব্যবহার করা উচিত ।

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


2
@ অ্যান্ড্রু লাজারাস, আপনি constকোনও constবস্তু থেকে দূরে ফেলতে পারবেন না , কেবল const X*কোনটি থেকে কোনটি নির্দেশ করে X। তবে সে কথাটি নয়; মুল বক্তব্যটি হ'ল স্বয়ংক্রিয় বস্তুগুলির স্থির ঠিকানা থাকতে পারে না। যেমনটি আমি বলেছি, constexprসংকলনটি শেষ হয়ে গেলে অর্থবহ হওয়া বন্ধ হয়ে যায়, তাই ফেলে দেওয়ার মতো কিছুই নেই (এবং সম্ভবত বেশিরভাগ কিছুই কিছুই নেই, কারণ অবজেক্টটি রানটাইমের সময় উপস্থিত থাকার নিশ্চয়তাও দেয় না।)
রিচি

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

2
@ void.pointer: আপনি শেষ অনুচ্ছেদে ঠিক বলেছেন about আমি পরিচিতি পরিবর্তন করেছি। আমি ভেবেছিলাম যে আমি এর গুরুত্বটি ব্যাখ্যা করেছি static constexpr(এটি প্রতিটি ক্রিয়াকলাপে পুনরায় তৈরি করা থেকে ধ্রুবক অ্যারে প্রতিরোধ করে) তবে আমি এমন কিছু শব্দ টুইট করেছি যা এটি আরও পরিষ্কার করে দিতে পারে। ধন্যবাদ।
ধনী

8
রান টাইম ধ্রুবক বনাম সংকলন টাইমস্ট্যান্ট উল্লেখ করার জন্যও দরকারী হতে পারে। অন্য কথায়, যদি একটি constexprধ্রুবক পরিবর্তনশীল কেবল সংকলন-সময় প্রসঙ্গে ব্যবহৃত হয় এবং রানটাইমের সময় কখনও প্রয়োজন হয় না, তারপরে staticকোনও অর্থ হয় না, যেহেতু আপনি রানটাইমটিতে পৌঁছানোর পরে মানটি কার্যকরভাবে "ইনলাইনড" হয়েছে। যাইহোক, যদি constexprরানটাইম প্রসঙ্গে ব্যবহার করা হয় (অন্য কথায়, এটি স্পষ্টত constexprরূপান্তরিত করতে হবে const, এবং রানটাইম কোডের জন্য একটি শারীরিক ঠিকানা সহ উপলভ্য হবে) এটি staticওডিআর সম্মতি নিশ্চিত করতে চাইবে ইত্যাদি That এটি আমার বুঝতে অন্ততপক্ষে।
void.pointer

3
আমার শেষ মন্তব্যের জন্য একটি উদাহরণ: static constexpr int foo = 100;। কোডের মতো কিছু না করা থাকলে কম্পাইলারটি fooআক্ষরিক জন্য সর্বত্রের ব্যবহারের বিকল্প নিতে পারে না এমন কোনও কারণ নেই । সুতরাং উপর থেকে এই ক্ষেত্রে কোন উপযোগিতা আছে রানটাইম এ কোন অস্তিত্ব নেই। আবার সব সংকলক পর্যন্ত। 100&foostaticfoofoo
void.pointer

10

প্রদত্ত উত্তরের পাশাপাশি, এটি লক্ষণীয় যে কম্পাইলারটি constexprসংকলনের সময় চলকটি আরম্ভ করার দরকার নেই , এটি জেনে যে পার্থক্যটি constexprএবং এটির static constexprব্যবহারের জন্য static constexprআপনি নিশ্চিত হন যে ভেরিয়েবলটি একবারেই আরম্ভ করা হয়েছিল।

নিম্নলিখিত কোডটি দেখায় যে constexprপরিবর্তনশীল একাধিকবার (যদিও একই মান সহ) static constexprআরম্ভ করা হয় , তবে অবশ্যই একবারেই আরম্ভ করা হয়।

সংযুক্তির সাথে কোডের constexprবিপরীতে সুবিধার তুলনা করা constহয় static

#include <iostream>
#include <string>
#include <cassert>
#include <sstream>

const short const_short = 0;
constexpr short constexpr_short = 0;

// print only last 3 address value numbers
const short addr_offset = 3;

// This function will print name, value and address for given parameter
void print_properties(std::string ref_name, const short* param, short offset)
{
    // determine initial size of strings
    std::string title = "value \\ address of ";
    const size_t ref_size = ref_name.size();
    const size_t title_size = title.size();
    assert(title_size > ref_size);

    // create title (resize)
    title.append(ref_name);
    title.append(" is ");
    title.append(title_size - ref_size, ' ');

    // extract last 'offset' values from address
    std::stringstream addr;
    addr << param;
    const std::string addr_str = addr.str();
    const size_t addr_size = addr_str.size();
    assert(addr_size - offset > 0);

    // print title / ref value / address at offset
    std::cout << title << *param << " " << addr_str.substr(addr_size - offset) << std::endl;
}

// here we test initialization of const variable (runtime)
void const_value(const short counter)
{
    static short temp = const_short;
    const short const_var = ++temp;
    print_properties("const", &const_var, addr_offset);

    if (counter)
        const_value(counter - 1);
}

// here we test initialization of static variable (runtime)
void static_value(const short counter)
{
    static short temp = const_short;
    static short static_var = ++temp;
    print_properties("static", &static_var, addr_offset);

    if (counter)
        static_value(counter - 1);
}

// here we test initialization of static const variable (runtime)
void static_const_value(const short counter)
{
    static short temp = const_short;
    static const short static_var = ++temp;
    print_properties("static const", &static_var, addr_offset);

    if (counter)
        static_const_value(counter - 1);
}

// here we test initialization of constexpr variable (compile time)
void constexpr_value(const short counter)
{
    constexpr short constexpr_var = constexpr_short;
    print_properties("constexpr", &constexpr_var, addr_offset);

    if (counter)
        constexpr_value(counter - 1);
}

// here we test initialization of static constexpr variable (compile time)
void static_constexpr_value(const short counter)
{
    static constexpr short static_constexpr_var = constexpr_short;
    print_properties("static constexpr", &static_constexpr_var, addr_offset);

    if (counter)
        static_constexpr_value(counter - 1);
}

// final test call this method from main()
void test_static_const()
{
    constexpr short counter = 2;

    const_value(counter);
    std::cout << std::endl;

    static_value(counter);
    std::cout << std::endl;

    static_const_value(counter);
    std::cout << std::endl;

    constexpr_value(counter);
    std::cout << std::endl;

    static_constexpr_value(counter);
    std::cout << std::endl;
}

সম্ভাব্য প্রোগ্রাম আউটপুট:

value \ address of const is               1 564
value \ address of const is               2 3D4
value \ address of const is               3 244

value \ address of static is              1 C58
value \ address of static is              1 C58
value \ address of static is              1 C58

value \ address of static const is        1 C64
value \ address of static const is        1 C64
value \ address of static const is        1 C64

value \ address of constexpr is           0 564
value \ address of constexpr is           0 3D4
value \ address of constexpr is           0 244

value \ address of static constexpr is    0 EA0
value \ address of static constexpr is    0 EA0
value \ address of static constexpr is    0 EA0

আপনি দেখতে পাচ্ছেন যে নিজেকে constexprএকাধিকবার সূচনা করা হয়েছে (ঠিকানাটি একই নয়) এবং staticকীওয়ার্ড নিশ্চিত করে যে একবারে আরম্ভ করা হয়।


আমরা ব্যবহার করতে পারেন constexpr const short constexpr_shortত্রুটি দেবার জন্য যদি constexpr_short আবার সক্রিয়া করা হয়
akhileshzmishra

আপনার সিনট্যাক্সটি constexpr constকোনও অর্থবোধ করে না কারণ constexprইতিমধ্যে const, constসংকলক দ্বারা একবার বা একাধিকবার যুক্ত করা উপেক্ষা করা হয়। আপনি একটি ত্রুটি ধরার চেষ্টা করছেন তবে এটি কোনও ত্রুটি নয়, বেশিরভাগ সংকলক কাজ করেন।
মেটাব্লাস্টার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.