স্ট্যাটিক_সেটর কী করে এবং আপনি কীসের জন্য এটি ব্যবহার করবেন?


117

আপনি কি উদাহরণ দিতে পারেন যেখানে static_assert(...)('সি ++ 11') হাতের মুঠোয় সমস্যার সমাধান করবে?

আমি রান-টাইমের সাথে পরিচিত assert(...)। আমি কখন static_assert(...)নিয়মিত চেয়ে বেশি পছন্দ করি assert(...)?

এছাড়াও, boostসেখানে কিছু বলা হয় BOOST_STATIC_ASSERT, এটি কি একই রকম static_assert(...)?


এছাড়াও দেখুন: BOOST_MPL_ASSERT, BOOST_MPL_ASSERT_NOT, BOOST_MPL_ASSERT_MSG, BOOST_MPL_ASSERT_RELATION [ boost.org/doc/libs/1_40_0/libs/mpl/doc/refmanual/asserts.httstts । আপনি কীভাবে এটি ব্যবহার করবেন তা বুঝতে পেরে _এমএসজি বিশেষত দুর্দান্ত।
কিটসুনওয়াইএমজি

উত্তর:


82

আমার মাথার উপরে...

#include "SomeLibrary.h"

static_assert(SomeLibrary::Version > 2, 
         "Old versions of SomeLibrary are missing the foo functionality.  Cannot proceed!");

class UsingSomeLibrary {
   // ...
};

ধরে নিই যে SomeLibrary::Versionএটি #defineডি হওয়ার পরিবর্তে স্থিতিশীল কনস্ট হিসাবে ঘোষিত হয়েছে (যেমন একটি সি ++ লাইব্রেরিতে প্রত্যাশা করা হবে)।

আসলে SomeLibraryআপনার সংকলন এবং আপনার কোডটি সংযুক্ত করা, সমস্ত কিছু লিঙ্ক করা এবং কেবলমাত্র তখনই এক্সিকিউটেবল চালানো যা আপনি একটি বেমানান সংস্করণ সংকলন 30 মিনিট ব্যয় করেছেন তা জানতে পার্থক্য করুন SomeLibrary

@ আরাক, আপনার মন্তব্যের জবাবে: হ্যাঁ, আপনি static_assertযেখানেই থাকুন না কেন, তার চেহারা থেকে এখানে বসে থাকতে পারেন:

class Foo
{
    public: 
        static const int bar = 3;
};

static_assert(Foo::bar > 4, "Foo::bar is too small :(");

int main()
{ 
    return Foo::bar;
}
$ g ++ --std = c ++ 0x a.cpp
a.cpp: 7: ত্রুটি: স্থিতিশীল দাবি ব্যর্থ হয়েছে: "ফু :: বারটি খুব ছোট :("

1
আমি কিছুটা বিভ্রান্ত হয়ে পড়েছি, আপনি কি static_assertকার্যকর করতে পারবেন না ? এটি খুব সুন্দর উদাহরণ বলে মনে হচ্ছে :)
আরাক

3
হ্যাঁ, স্থির দাবী হিসাবে তারা দাঁড়ায় সাধারণত একটি বস্তু তৈরির হিসাবে প্রয়োগ করা হয় যা কেবলমাত্র সংজ্ঞায়িত সত্য হলেই সংজ্ঞায়িত হয়। এটি কেবল একটি বৈশ্বিক করে তুলবে।
GManNickG

আমি নিশ্চিত নই যে এটি সম্পূর্ণরূপে মূল প্রশ্নের উত্তর হিসাবে যোগ্যতা অর্জন করেছে, তবে দুর্দান্ত বিক্ষোভ
ম্যাট জয়েনার

2
কি পার্থক্য এই উত্তরে কোনো বিবরণ উপলব্ধ করা হয় না জাহির থেকে <cassert> এবং static_assert
bitek

11
@ মোমোকোডার: অনুচ্ছেদটি "বিপরীতে ..." দিয়ে শুরু করুন দেখুন। সংক্ষেপে বলতে গেলে: জাহির চেক রানটাইম তার শর্ত, এবং static_assert চেক সংকলন তার অবস্থা। সুতরাং আপনি যে শর্তটি বলছেন তা সংকলনের সময় জানা থাকলে, ব্যবহার করুন static_assert। প্রোগ্রামটি চালা না হওয়া পর্যন্ত যদি শর্তটি জানা না যায় তবে ব্যবহার করুন assert
মাইক ডিসিমোন 3'13

131

সংকলন সময়ে স্থিতিশীল সংস্থান ব্যবহার করা হয়। যখন স্থিতিশীল দৃser়তা ব্যর্থ হয়, প্রোগ্রামটি সহজেই সংকলন করে না। এটি বিভিন্ন পরিস্থিতিতে যেমন দরকারী, উদাহরণস্বরূপ, আপনি যদি কোড দ্বারা কিছু কার্যকারিতা প্রয়োগ করেন যা সমালোচনামূলকভাবে unsigned intঅবজেক্টের উপর নির্ভর করে 32 টি বিট রাখে। আপনি এটির মতো একটি স্ট্যাটিক সংস্থান রাখতে পারেন

static_assert(sizeof(unsigned int) * CHAR_BIT == 32);

আপনার কোডে অন্য একটি প্ল্যাটফর্মে, বিভিন্ন আকারের unsigned intসংকলনটি ব্যর্থ হবে, এইভাবে কোডটির সমস্যাযুক্ত অংশের দিকে বিকাশকারীদের দৃষ্টি আকর্ষণ করবে এবং এটিকে পুনরায় বাস্তবায়ন বা পুনরায় পরীক্ষা করার পরামর্শ দেবে।

অন্য উদাহরণের জন্য, আপনি void *কোনও ফাংশনে পয়েন্টার হিসাবে কিছু অবিচ্ছেদ্য মান পাস করতে চাইতে পারেন (একটি হ্যাক, তবে সময়ে দরকারী) এবং আপনি নিশ্চিত করতে চান যে ইন্টিগ্রাল মান পয়েন্টারের সাথে খাপ খায়?

int i;

static_assert(sizeof(void *) >= sizeof i);
foo((void *) i);

আপনি সেই charধরণের স্বাক্ষরিত সম্পদটি চাইতে পারেন

static_assert(CHAR_MIN < 0);

বা negativeণাত্মক মানগুলির সাথে অবিচ্ছেদ্য বিভাগটি শূন্যের দিকে যায়

static_assert(-5 / 2 == -2);

ইত্যাদি।

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

অবশ্যই, স্থির দৃ as়তার মধ্যে প্রকাশটি একটি সংকলন-সময় ধ্রুবক হতে হবে। এটি রান-টাইম মান হতে পারে না। রান-টাইম মানগুলির জন্য আপনার কাছে সাধারণ ব্যবহার ছাড়া আর কোনও পছন্দ নেই assert


3
স্ট্যাটিক_সেটরটি দ্বিতীয় প্যারামিটার হিসাবে স্ট্রিং আক্ষরিক থাকার প্রয়োজন হয় না?
ট্রেভর হিকি

3
@ ট্র্যাভর হিকি: হ্যাঁ, তাই। তবে আমি static_assertবিশেষত সি ++ 11 থেকে উল্লেখ করার চেষ্টা করছিলাম না । আমার static_assertউপরের স্থিতিশীল দাবিগুলির কিছু বিমূর্ত বাস্তবায়ন। (আমি ব্যক্তিগতভাবে সি কোডে এরকম কিছু ব্যবহার করি)। আমার উত্তরটি স্থির প্রতিবেদনের সাধারণ উদ্দেশ্য এবং রান-টাইম জোর দেওয়া থেকে তাদের পার্থক্য সম্পর্কে উদ্দেশ্য।
এন্টি

প্রথম উদাহরণে, আপনি ধরে নিচ্ছেন যে কোনও ধরণের ভেরিয়েবলে প্যাডিং বিট নেই unsigned int। এটি মানদণ্ডের দ্বারা নিশ্চিত নয়। বিভিন্ন ধরণের বৈকল্পিক unsigned intআইনীভাবে মেমরির 32 বিট দখল করতে পারে, যার মধ্যে 16 টি অব্যবহৃত (এবং এইভাবে ম্যাক্রোর UINT_MAXসমান হবে 65535)। পথ সুতরাং আপনি প্রথম স্ট্যাটিক কথন ( "বর্ণনা unsigned intবস্তু থাকার ঠিক 32 বিট") বিভ্রান্তিকর করা হয়। আপনার বর্ণনার সাথে মেলে করার জন্য, এই বিবৃতি হিসাবে ভাল অন্তর্ভুক্ত করা উচিত: static_assert(UINT_MAX >= 0xFFFFFFFFu)
রাল্ফস

@ ট্র্যাভের হিক্কি আর নেই (সি ++ 17)
লুইজফ্লস

13

সংকলক আচরণ, শিরোনাম, libs এবং এমনকি আমার নিজের কোডটি সঠিক কিনা তা সম্পর্কে আমার অনুমানগুলি নিশ্চিত করতে আমি এটি ব্যবহার করি। উদাহরণস্বরূপ এখানে আমি যাচাই করেছি যে স্ট্রাক্টটি সঠিকভাবে প্রত্যাশিত আকারে প্যাক করা হয়েছে।

struct LogicalBlockAddress
{
#pragma pack(push, 1)
    Uint32 logicalBlockNumber;
    Uint16 partitionReferenceNumber;
#pragma pack(pop)
};
BOOST_STATIC_ASSERT(sizeof(LogicalBlockAddress) == 6);

একটি বর্গ মোড়ানো সালে stdio.h'র fseek(), আমি সঙ্গে কিছু শর্টকাট গ্রহণ করেছে enum Originপরীক্ষক সেই শর্টকাট ধ্রুবক দ্বারা সংজ্ঞায়িত দিয়ে সারিবদ্ধstdio.h

uint64_t BasicFile::seek(int64_t offset, enum Origin origin)
{
    BOOST_STATIC_ASSERT(SEEK_SET == Origin::SET);

সংকলনের সময় আচরণটি সংজ্ঞায়িত static_assertহওয়ার assertপরে আপনার পছন্দ করা উচিত , এবং রানটাইমের সময় নয়, যেমন আমি উপরে উদাহরণ দিয়েছি। উদাহরণস্বরূপ যেখানে এটি নয় এটি প্যারামিটার এবং রিটার্ন কোড চেকিং অন্তর্ভুক্ত করবে।

BOOST_STATIC_ASSERTশর্তটি সন্তুষ্ট না হলে একটি প্রি-সি ++ 0 এক্স ম্যাক্রো যা অবৈধ কোড উত্পন্ন করে। উদ্দেশ্যগুলি একই, যদিও static_assertমানক করা হয় এবং আরও ভাল সংকলক ডায়াগনস্টিক্স সরবরাহ করতে পারে।


9

BOOST_STATIC_ASSERTstatic_assertকার্যকারিতা জন্য একটি ক্রস প্ল্যাটফর্মের আবরণ ।

বর্তমানে আমি ক্লাসে "ধারণাগুলি" প্রয়োগ করার জন্য স্ট্যাটিক_সেটর ব্যবহার করছি।

উদাহরণ:

template <typename T, typename U>
struct Type
{
  BOOST_STATIC_ASSERT(boost::is_base_of<T, Interface>::value);
  BOOST_STATIC_ASSERT(std::numeric_limits<U>::is_integer);
  /* ... more code ... */
};

উপরের শর্তগুলির কোনওটি পূরণ না করা হলে এটি একটি সংকলন সময় ত্রুটির সৃষ্টি করবে


3
এখন যেহেতু সি ++ 11 আউট হয়েছে (এবং কিছুক্ষণের জন্য বাইরে চলে গেছে), স্ট্যাটিক_সেটরটি সমস্ত বড় সংকলকগুলির আরও সাম্প্রতিক সংস্করণ দ্বারা সমর্থন করা উচিত। আমাদের মধ্যে যারা সি ++ ১৪ (যা আশা করি টেমপ্লেটের সীমাবদ্ধতাগুলি ধারণ করবে) এর জন্য অপেক্ষা করতে পারে না, এটি স্ট্যাটিক_সেসার্টের একটি খুব দরকারী অ্যাপ্লিকেশন।
কলিন

7

এর একটি ব্যবহার static_assertনিশ্চিত করা যায় যে কোনও কাঠামো (এটি বাইরের বিশ্বের সাথে ইন্টারফেস, যেমন একটি নেটওয়ার্ক বা ফাইল) আপনার প্রত্যাশাটি হুবহু আকার। এটি এমন কেসগুলির মুখোমুখি হবে যেখানে ফলাফলটি উপলব্ধি না করে কেউ কাঠামো থেকে কোনও সদস্যকে যুক্ত বা সংশোধন করে। static_assertএটা নিতে এবং ব্যবহারকারী সতর্ক হবে।


3

ধারণার অনুপস্থিতিতে কেউ static_assertসাধারণ এবং পঠনযোগ্য সংকলন-টাইম পরীক্ষার জন্য ব্যবহার করতে পারে , উদাহরণস্বরূপ, টেমপ্লেটগুলিতে:

template <class T>
void MyFunc(T value)
{
static_assert(std::is_base_of<MyBase, T>::value, 
              "T must be derived from MyBase");

// ...
}

2

এটি সরাসরি আসল প্রশ্নের উত্তর দেয় না, তবে সি ++ 11 এর পূর্বে এই সংকলন টাইম চেকগুলি কীভাবে প্রয়োগ করা যায় সে সম্পর্কে একটি আকর্ষণীয় গবেষণা করে।

আন্ড্রেই আলেকজান্দারস্কু দ্বারা নির্মিত আধুনিক সি +++ এর অধ্যায় 2 (বিভাগ 2.1) এর মতো কমপাইল-টাইম জোরের এই ধারণাটি কার্যকর করে

template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};

#define STATIC_CHECK(expr, msg) \
{ CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; } 

ম্যাক্রো STATIC_CHECK () এবং স্ট্যাটিক_সেসার্ট () এর সাথে তুলনা করুন

STATIC_CHECK(0, COMPILATION_FAILED);
static_assert(0, "compilation failed");

-2

static_assertব্যবহারের নিষেধ ব্যবহার করা যেতে পারে deleteশব্দ এই ভাবে:

#define delete static_assert(0, "The keyword \"delete\" is forbidden.");

প্রতিটি আধুনিক সি ++ বিকাশকারী এটি করতে চাইলে তিনি যদি কেবল রক্ষণশীল আবর্জনা সংগ্রহকারীকে কেবল শ্রেণীর এস এবং স্ট্রাক্ট ব্যবহার করে রক্ষণশীল আবর্জনা সংগ্রাহকের রক্ষণশীল গাদাতে মেমরি বরাদ্দকারী অপারেটরটিকে নতুন করে ওভারলোড করেন যা ব্যবহার করতে চান ফাংশনের শুরুতে এটি করে এমন কিছু ফাংশন শুরু করে সূচনা এবং তাত্ক্ষণিক করা যেতে পারে main

উদাহরণস্বরূপ প্রতিটি আধুনিক সি ++ বিকাশকারী যে বোহেম-ডেমারস-ওয়েজার রক্ষণশীল আবর্জনা সংগ্রহকারী mainব্যবহার করতে চান সেগুলি ফাংশনের শুরুতে লিখতে হবে:

GC_init();

এবং প্রতিটি ক্ষেত্রে classএবং এইভাবে structওভারলোড করুন operator new:

void* operator new(size_t size)
{
     return GC_malloc(size);
}

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

একটি উপায় এইভাবে ওভারলোড হচ্ছে delete operator:

void operator delete(void* ptr)
{
    assert(0);
}

তবে এটির প্রস্তাব দেওয়া হয় না, কারণ আধুনিক সি ++ বিকাশকারীরা জানতে পারবেন যে সে delete operatorচালানোর সময় ভুল করে অনুরোধ করেছিল, তবে সংকলনের সময় শিগগিরই এটি জানা ভাল।

সুতরাং আমার মতে এই দৃশ্যের সর্বোত্তম সমাধান হ'ল static_assertএই উত্তরটির শুরুতে প্রদর্শিত হিসাবে ব্যবহার করা ।

অবশ্যই এটি দিয়েও করা যেতে পারে BOOST_STATIC_ASSERTতবে আমি মনে করি static_assertএটি আরও ভাল এবং আরও সবসময় পছন্দ করা উচিত।

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