Does C++ have “with” keyword like Pascal?

2019-01-19 10:48发布

问题:

with keyword in Pascal can be use to quick access the field of a record. Anybody knows if C++ has anything similar to that?

Ex: I have a pointer with many fields and i don't want to type like this:

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

what I really want is something like this in C++:

with (pointer)
{
  if (field1) && (field2) && .......(fieldn)
}

回答1:

In C++, you can put code in a method of the class being reference by pointer. There you can directly reference the members without using the pointer. Make it inline and you pretty much get what you want.



回答2:

Probably the closest you can get is this: (Please don't downvote me; this is just an academic exercise. Of course, you can't use any local variables in the body of these artificial with blocks!)

struct Bar {
    int field;
};

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

Or, a bit more demonically,

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

or in 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;


回答3:

no there is no such keyword.



回答4:

Even though I program mostly in Delphi which has a with keyword (since Delphi is a Pascal derivative), I don't use with. As others have said: it saves a bit on typing, but reading is made harder.

In a case like the code below it might be tempting to use 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;

Using with this looks like this

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

I prefer to use a different technique by introducing an extra variable pointing to the same thing with would be pointing to. Like this:

var lRecords: TDataSet;

lRecords := cxGrid.DBTableView.ViewData.Records;

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

This way there is no ambiguity, you save a bit on typing and the intent of the code is clearer than using with



回答5:

I like to use:

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

    #define END_WITH() }

Example:

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


回答6:

No, C++ does not have any such keyword.



回答7:

C++ does not have a feature like that. And many consider "WITH" in Pascal to be a problem because it can make the code ambiguous and hard to read, for example it hard to know if field1 is a member of pointer or a local variable or something else. Pascal also allows multiple with-variables such as "With Var1,Var2" which makes it even harder.



回答8:

The closest you can get is method chaining:

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

for setting multiple fields and using for namespaces.



回答9:

First I've heard that anybody doesn't like 'with'. The rules are perfectly straightforward, no different from what happens inside a class in C++ or Java. And don't overlook that it can trigger a significant compiler optimization.



回答10:

Having written numerous parsers, this seems like a dead simple list look up for the named object, either static or dynamic. Further, I have never seen a situation where the compiler did not correctly identify the missing object and type, so all those lame excuses for not allowing a WITH ...ENDWITH construction would seem to be a lot of hooey. For the rest of us prone to long object names one workaround is to create simple defines. Couldn't resist, suppose I have:

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


回答11:

with (OBJECT) {CODE}

There is no such thing in C++.
You can put CODE as is into a method of OBJECT, but it is not always desirable.

With C++11 you can get quite close by creating alias with short name for OBJECT.
For example code given in question it will look like so:

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

(The surrounding curly braces are used to limit visibility of alias _ )

If you use some field very often you can alias it directly:

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


回答12:

The following approach relies on Boost. If your compiler supports C++0x's auto then you can use that and get rid of the Boost dependence.

Disclaimer: please don't do this in any code that must be maintained or read by someone else (or even by yourself in a few months):

#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");
    }
}


回答13:

I can see one instance where 'with' is actually useful.

In methods for recursive data structures, you often have the case:

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

errors caused by typos like this are very hard to find.

With 'with' you could write

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

This probably doesn't outweight all the other negatives mentioned for 'with', but just as an interesting info...



回答14:

Maybe you can:

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

Or create a small program that will understand with statements in C++ and translate them to some form of a valid C++.



回答15:

No, there is no with keyword in C/C++.

But you can add it with some preprocessor code:

/* 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__))

Usage:

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

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

Simplified unoverloaded definitions (choose one):

unnamed (Kotlin style it):

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

named:

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

Of course the for loop always has only a single pass and will be optimized out by the compiler.