سؤال

هل يمكن أن تعطي مثالا حيث static_assert(...) 'C++0x' من شأنه أن يحل المشكلة في يد بأناقة؟

وأنا على دراية وقت التشغيل assert(...). متى يجب أن يفضل static_assert(...) على assert(...) العادية؟

وأيضا، في boost هناك شيء يسمى BOOST_STATIC_ASSERT، هل هو نفس static_assert(...)؟

هل كانت مفيدة؟

المحلول

ومن على قمة رأسي ...

#include "SomeLibrary.h"

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

class UsingSomeLibrary {
   // ...
};

وعلى افتراض وأعلن أن SomeLibrary::Version باعتباره CONST ثابت، بدلا من أن #defined (كما هو متوقع في C ++ مكتبة).

وعلى النقيض مع الحاجة إلى تجميع فعلا SomeLibrary والتعليمات البرمجية، ربط كل شيء، وتشغيل الملف القابل للتنفيذ فقط <م> ثم لمعرفة أن قضيت 30 دقيقة تجميع إصدار غير متوافق من SomeLibrary.

وArak، ردا على تعليقك: نعم، هل يمكن أن يكون 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: error: static assertion failed: "Foo::bar is too small :("

نصائح أخرى

يستخدم

وASSERT ثابت لجعل التأكيدات في وقت الترجمة. عندما فشل التأكيد ثابت، البرنامج ببساطة لا ترجمة. وهذا مفيد في حالات مختلفة، مثل، على سبيل المثال، إذا قمت بتطبيق بعض الوظائف عن طريق الرمز الذي يعتمد بشكل كبير على وجوه unsigned int وجود بالضبط 32 بت. يمكنك وضع ASSERT ثابت مثل هذا

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);

وأو أن الانقسام لا يتجزأ مع القيم السلبية جولات باتجاه الصفر

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

وهلم جرا.

وتأكيدات وقت التشغيل في كثير من الحالات يمكن استخدام بدلا من تأكيدات ثابتة، ولكن وقت التشغيل التأكيدات تعمل فقط في وقت التشغيل، وفقط عندما يمر السيطرة على التأكيد. لهذا السبب لعدم تأكيد وقت التشغيل قد وضع نائمة، لم يتم كشفها لفترات طويلة من الزمن.

وبطبيعة الحال، فإن التعبير في التأكيد ثابت يجب أن يكون ثابت وقت الترجمة. لا يمكن أن تكون قيمة وقت التشغيل. للقيم وقت التشغيل لديك أي خيار آخر سوى استخدام assert العادي.

وأنا استخدامها لضمان بلدي افتراضات حول السلوك مترجم، رؤوس، يبس وحتى قانون بلدي الخاصة صحيحة. على سبيل المثال هنا يمكنني التحقق من البنية تم معبأة بشكل صحيح إلى الحجم المتوقع.

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 هو قبل C ++ 0X الماكرو الذي ينشئ رمز غير قانوني إذا كان الشرط غير راض. النوايا هي نفسها، وإن كان static_assert غير موحدة ويمكن أن توفر التشخيص مترجم أفضل.

وBOOST_STATIC_ASSERT هو مجمع عبر منصة حصول على وظائف static_assert.

وحاليا أنا باستخدام static_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 ... */
};

وهذا سوف يؤدي إلى خطأ وقت الترجمة إذا لم تتحقق أي من الشروط المذكورة أعلاه.

واستخدام واحدة من static_assert قد يكون للتأكد من أن هيكل (وهذا هو التفاعل مع العالم الخارجي، مثل الشبكة أو الملف) هو بالضبط الحجم الذي كنت تتوقع. هذا من شأنه أن قبض الحالات حيث يضيف شخص أو يعدل عضو من هيكل دون أن يدركوا العواقب. ان static_assert يستلم وتنبيه المستخدم.

في غياب مفاهيم يمكن للمرء أن استخدام static_assert للبسيط ويمكن قراءتها في وقت التجميع نوع التحقق، على سبيل المثال، في قوالب:

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

// ...
}

وهذا لا يجيب مباشرة على السؤال الأصلي، ولكن يجعل الدراسة مثيرة للاهتمام في كيفية تطبيق هذه تجميع الشيكات وقت قبل C ++ 11.

والفصل 2 (القسم 2.1) من تصميم ++ C الحديثة اندريه Alexanderscu ينفذ هذا فكرة تأكيدات ترجمة-مثل هذا الوقت

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

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

وقارن STATIC_CHECK الماكرو () وstatic_assert ()

STATIC_CHECK(0, COMPILATION_FAILED);
static_assert(0, "compilation failed");
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top