سؤال

with يمكن استخدام الكلمة الرئيسية في Pascal للوصول السريع إلى حقل السجل. أي شخص يعرف ما إذا كان C ++ لديه أي شيء مشابه لذلك؟

على سبيل المثال: لدي مؤشر مع العديد من الحقول ولا أريد أن أكتب مثل هذا:

if (pointer->field1) && (pointer->field2) && ... (pointer->fieldn)

ما أريده حقًا هو شيء من هذا القبيل في C ++:

with (pointer)
{
  if (field1) && (field2) && .......(fieldn)
}
هل كانت مفيدة؟

المحلول

في C ++ ، يمكنك وضع الرمز بطريقة يتم الإشارة إلى الفئة بواسطة pointer. هناك يمكنك الرجوع مباشرة إلى الأعضاء دون استخدام المؤشر. أصنعها inline وأنت تحصل على ما تريد.

نصائح أخرى

ربما الأقرب الذي يمكنك الحصول عليه هو: (من فضلك لا تخدعني ؛ هذا مجرد تمرين أكاديمي. بالطبع ، لا يمكنك استخدام أي متغيرات محلية في نص هذه الاصطناعية with كتل!)

struct Bar {
    int field;
};

void foo( Bar &b ) {
    struct withbar : Bar { void operator()() {
        cerr << field << endl;
    }}; static_cast<withbar&>(b)();
}

أو ، أكثر شيطانية ،

#define WITH(T) do { struct WITH : T { void operator()() {
#define ENDWITH(X) }}; static_cast<WITH&>((X))(); } while(0)

struct Bar {
    int field;
};

void foo( Bar &b ) {
    if ( 1+1 == 2 )
        WITH( Bar )
            cerr << field << endl;
        ENDWITH( b );
}

أو في C ++ 0x

#define WITH(X) do { auto P = &X; \
 struct WITH : typename decay< decltype(X) >::type { void operator()() {
#define ENDWITH }}; static_cast<WITH&>((*P))(); } while(0)

        WITH( b )
            cerr << field << endl;
        ENDWITH;

لا ، لا توجد مثل هذه الكلمة الرئيسية.

أحب استخدام:

    #define BEGIN_WITH(x) { \
        auto &_ = x;

    #define END_WITH() }

مثال:

    BEGIN_WITH(MyStructABC)
    _.a = 1;
    _.b = 2;
    _.c = 3;
    END_WITH()

على الرغم من أنني برمجة في الغالب في دلفي التي لديها with الكلمة الرئيسية (نظرًا لأن Delphi مشتق Pascal) ، لا أستخدم with. كما قال آخرون: إنه يحفظ قليلاً على الكتابة ، لكن القراءة أصبحت أكثر صعوبة.

في حالة مثل الكود أدناه ، قد يكون من المغري استخدامه with:

cxGrid.DBTableView.ViewData.Records.FieldByName('foo').Value = 1;
cxGrid.DBTableView.ViewData.Records.FieldByName('bar').Value = 2;
cxGrid.DBTableView.ViewData.Records.FieldByName('baz').Value = 3;

استخدام with هذا يبدو مثل هذا

with cxGrid.DBTableView.ViewData.Records do
begin
  FieldByName('foo').Value = 1;
  FieldByName('bar').Value = 2;
  FieldByName('baz').Value = 3;
end;

أفضل استخدام تقنية مختلفة عن طريق تقديم متغير إضافي يشير إلى نفس الشيء with سوف تشير إلى. مثله:

var lRecords: TDataSet;

lRecords := cxGrid.DBTableView.ViewData.Records;

lRecords.FieldByName('foo').Value = 1;
lRecords.FieldByName('bar').Value = 2;
lRecords.FieldByName('baz').Value = 3;

وبهذه الطريقة لا يوجد غموض ، يمكنك حفظ بعض الشيء على الكتابة والقصد من الكود أكثر وضوحًا من استخدام with

لا ، لا يحتوي C ++ على أي كلمة رئيسية من هذا القبيل.

لا يحتوي C ++ على ميزة من هذا القبيل. ويعتبر الكثيرون أن "مع" في باسكال يمثل مشكلة لأنه يمكن أن يجعل الكود غامضًا ويصعب قراءته ، على سبيل المثال أنه من الصعب معرفة ما إذا كان الحقل 1 عضوًا في المؤشر أو متغير محلي أو أي شيء آخر. يتيح Pascal أيضًا العديد من المتغيرات مثل "مع var1 ، var2" مما يجعل الأمر أكثر صعوبة.

الأقرب الذي يمكنك الحصول عليه هو طريقة السلاسل:

myObj->setX(x)
     ->setY(y)
     ->setZ(z)

لوضع حقول متعددة و using لمساحات الأسماء.

with (OBJECT) {CODE}

لا يوجد شيء من هذا القبيل في C ++.
يمكنك وضع التعليمات البرمجية كما هي في طريقة الكائن ، لكنها ليست مرغوبة دائمًا.

مع C ++ 11 ، يمكنك الاقتراب عن طريق إنشاء الاسم المستعار مع اسم قصير للكائن.
على سبيل المثال الرمز الوارد في السؤال ، سيبدو هكذا:

{
    auto &_ = *pointer;
    if (_.field1 && ... && _.fieldn) {...}
}

(يتم استخدام الأقواس المجعد المحيطة للحد من رؤية الاسم المستعار _ )

إذا كنت تستخدم بعض الحقل في كثير من الأحيان ، فيمكنك التلقائي مباشرة:

auto &field = pointer->field;
// Even shorter alias:
auto &_ = pointer->busy_field;

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

بعد أن كتبت العديد من المحللين ، يبدو أن قائمة بسيطة ميتة تبحث عن الكائن المسماة ، إما ثابتًا أو ديناميكيًا. علاوة على ذلك ، لم أر قط موقفًا لم يحدد فيه المترجم بشكل صحيح الكائن والنوع المفقود بشكل صحيح ، لذلك يبدو أن كل تلك الأعذار العرجاء لعدم السماح بـ ... endwith بناء الكثير من hooey. بالنسبة لبقية منا عرضة لأسماء الكائنات الطويلة ، فإن أحد الحلول هو إنشاء تعريفات بسيطة. لم أستطع المقاومة ، لنفترض أن لدي:

    #include<something> 
    typedef int headache;
    class grits{
      public:
       void corn(void);
       void cattle(void);
       void hay(void);}; //insert function defs here
     void grits::grits(void)(printf("Welcome to Farm-o-mania 2012\n");};

    #define m mylittlepiggy_from_under_the_backporch.
    headache main(){
       grits mylittlepiggy_from_under_the_backporch;
         m corn();  //works in GCC
         m cattle();
         m hay();
      return headache;

النهج التالي يعتمد على التعزيز. إذا كان المترجم الخاص بك يدعم C ++ 0x's auto ثم يمكنك استخدام ذلك والتخلص من الاعتماد على التعزيز.

عدم اعطاء رأي: من فضلك لا تفعل ذلك في أي رمز يجب الحفاظ عليه أو قراءته من قبل شخص آخر (أو حتى بنفسك في غضون بضعة أشهر):

#define WITH(src_var)                                             \
    if(int cnt_ = 1)                                              \
        for(BOOST_AUTO(const & _, src_var); cnt_; --cnt_)


int main()
{
    std::string str = "foo";

    // Multiple statement block
    WITH(str)
    {
        int i = _.length();
        std::cout << i << "\n";
    }

    // Single statement block
    WITH(str)
        std::cout << _ << "\n";

    // Nesting
    WITH(str)
    {
        std::string another("bar");
        WITH(another)
            assert(_ == "bar");
    }
}

أستطيع أن أرى مثيلًا واحدًا حيث "مع" مفيد بالفعل.

في طرق هياكل البيانات العودية ، غالبًا ما يكون لديك الحالة:

void A::method()
{
  for (A* node = this; node; node = node->next) {
    abc(node->value1);
    def(value2); // -- oops should have been node->value2
    xyz(node->value3);
  }
}

من الصعب للغاية العثور على الأخطاء الناجمة عن الأخطاء المطبعية مثل هذه.

مع "مع" يمكنك الكتابة

void A::method()
{
  for (A* node = this; node; node = node->next) with (node) {
    abc(value1);
    def(value2);
    xyz(value3);
  }
}

ربما لا يفوق هذا كل السلبيات الأخرى المذكورة لـ "مع" ، ولكن كمعلومات مثيرة للاهتمام ...

ربما يمكنك:

auto p = *pointer;
if (p.field1) && (p.field2) && ... (p.fieldn)

أو قم بإنشاء برنامج صغير سوف يفهم with عبارات في C ++ وترجمتها إلى شكل من أشكال C ++ صالحة.

لا ، لا يوجد with الكلمة الرئيسية في C/C ++.

ولكن يمكنك إضافته مع بعض رمز المعالج المسبق:

/* Copyright (C) 2018 Piotr Henryk Dabrowski, Creative Commons CC-BY 3.0 */

#define __M2(zero, a1, a2, macro, ...) macro

#define __with2(object, as) \
    for (typeof(object) &as = (object), *__i = 0; __i < (void*)1; ++__i)

#define __with1(object) __with2(object, it)

#define with(...) \
    __M2(0, ##__VA_ARGS__, __with2(__VA_ARGS__), __with1(__VA_ARGS__))

الاستخدام:

with (someVeryLongObjectNameOrGetterResultOrWhatever) {
    if (it)
        it->...
    ...
}

with (someVeryLongObjectNameOrGetterResultOrWhatever, myObject) {
    if (myObject)
        myObject->...
    ...
}

تعاريف مبسطة غير محملة (اختر واحدة):

لم يذكر اسمه (أسلوب Kotlin it):

#define with(object) \
    for (typeof(object) &it = (object), *__i = 0; __i < (void*)1; ++__i)

اسم الشيئ:

#define with(object, as) \
    for (typeof(object) &as = (object), *__i = 0; __i < (void*)1; ++__i)

بالطبع for تحتوي الحلقة دائمًا على تمريرة واحدة فقط وسيتم تحسينها من قبل المترجم.

#include <iostream>

using namespace std;

template <typename T>
struct with_iter {
  with_iter( T &val ) : p(&val) {}

  inline T* begin() { return p; }
  inline T* end() { return p+1; }

  T *p;
};

#define with( N, I ) for( auto &N : with_iter<decltype(I)>(I) )

int main() {

  with( out , cout ) {
    out << "Hello world!" << endl;
  }

  return 0;
}

قال نوف ...

طريقة بسيطة للقيام بذلك هي على النحو التالي

class MyClass
{
    int& m_x;

    public MyClass(int& x)
    {
        m_x = x;
        m_x++;
    }

    ~MyClass()
    {
        m_x--;
    }
}
int main():
{
    x = 0;
    {
        MyClass(x)  // x == 1 whilst in this scope
    }
}

لقد كنت أكتب Python طوال اليوم وألغت هذا الأمر قبل أن يأخذني أي شخص إلى عمال النظافة. في برنامج أكبر ، هذا مثال على كيفية الحفاظ على عدد موثوق به لشيء ما.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top