C ++是否有像Pascal这样的“with”关键字?

时间:2010-02-17 08:19:44

标签: c++ pascal with-statement

Pascal中的

with关键字可用于快速访问记录的字段。 有谁知道C ++是否有类似的东西?

例: 我有一个包含许多字段的指针,我不想这样输入:

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

我真正想要的是C ++中的这样的东西:

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

19 个答案:

答案 0 :(得分:19)

你可以得到的最接近的是:(请不要向我投票;这只是一个学术练习。当然,你不能在这些人工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;

答案 1 :(得分:12)

没有这样的关键字。

答案 2 :(得分:9)

在C ++中,您可以将代码放在pointer引用的类的方法中。在那里你可以直接引用成员而不使用指针。把它inline,你几乎得到你想要的东西。

答案 3 :(得分:8)

即使我主要使用具有with关键字的Delphi编程(因为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

更清晰

答案 4 :(得分:8)

我喜欢使用:

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

    #define END_WITH() }

示例:

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

答案 5 :(得分:5)

C ++没有这样的功能。许多人认为Pascal中的“WITH”是一个问题,因为它可能使代码含糊不清并且难以阅读,例如很难知道field1是指针的成员还是局部变量或其他东西。 Pascal还允许多个带变量,例如“With Var1,Var2”,这使得它更难。

答案 6 :(得分:4)

不,C ++没有任何此类关键字。

答案 7 :(得分:4)

最接近的是method chaining

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

用于设置多个字段,using用于命名空间。

答案 8 :(得分:1)

首先我听说有人不喜欢'和'。规则非常简单,与C ++或Java中的类内部没有什么不同。并且不要忽视它可以触发重要的编译器优化。

答案 9 :(得分:1)

编写了大量的解析器后,这看起来像一个死的简单列表,可以查找命名对象,无论是静态还是动态。此外,我从未见过编译器没有正确识别丢失的对象和类型的情况,因此所有那些不允许使用WITH ... ENDWITH构造的蹩脚借口似乎很多。对于我们其他人倾向于长对象名称,一种解决方法是创建简单的定义。无法抗拒,假设我有:

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

答案 10 :(得分:1)

with (OBJECT) {CODE}

C ++中没有这样的东西 您可以将CODE原样放入OBJECT方法中,但并不总是可取。

使用C ++ 11,您可以通过为OBJECT创建短名称别名来实现目标 例如,给出的代码看起来就像这样:

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

(周围的花括号用于限制别名_)的可见性

如果您经常使用某个字段,可以直接使用别名:

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

答案 11 :(得分:0)

我对 PotatoSwatter(目前接受的答案)感到遗憾,我无法使用该解决方案访问封闭范围中声明的变量。 我试图在对 PotatoSwatter 的评论回复中发布这个,但作为整篇文章更好。有点过头了,但语法糖非常好!

#define WITH_SIG float x, float y, float z
#define WITH_ARG x, y, z

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

class MyClass {
    Vector memberVector;
    static void myFunction(MyClass* self, WITH_SIG) {
        WITH(MyClass, WITH_SIG)
            memberVector = Vector(x,y,z);
        ENDWITH(*self, WITH_ARG);
    }
}

答案 12 :(得分:0)

我也来自 Pascal 世界..... ..... 而且我也喜欢 Python 对 with 的使用(基本上是自动尝试/finally):

  with open(filename, "r") as file:
    for line in file:
      if line.startswith("something"):
        do_more()

这就像一个智能 ptr 对象。如果打开失败,它不会进入块;离开块时,文件是否关闭。

这是一个非常接近 Pascal 的示例,同时也支持 Python 的使用(假设您有一个带有析构函数清理的智能对象);您需要更新的 C++ 标准编译器才能工作。

    // Old way
    cxGrid_s cxGrid{};
    cxGrid.DBTableView.ViewData.Records.FieldByName.value["foo"] = 1;
    cxGrid.DBTableView.ViewData.Records.FieldByName.value["bar"] = 2;
    cxGrid.DBTableView.ViewData.Records.FieldByName.value["baz"] = 3;
    // New Way - FieldByName will now be directly accessible.
    // the `;true` is only needed if the call does not return bool or pointer type
    if (auto FieldByName = cxGrid.DBTableView.ViewData.Records.FieldByName; true)
    {
        FieldByName.fn1 = 0;
        FieldByName.fn2 = 3;
        FieldByName.value["foo"] = 1;
        FieldByName.value["bar"] = 2;
        FieldByName.value["baz"] = 3;
    }

如果你想更近一点:

    #define with if

    with (auto FieldByName = cxGrid.DBTableView.ViewData.Records.FieldByName; true)
    // Similar to the Python example
    with (smartFile sf("c:\\file.txt"); sf)
    {
        fwrite("...", 1, 3, *sf);
    }
    // Usage with a smart pointer
    with (std::unique_ptr<class_name> p = std::make_unique<class_name>())
    {
        p->DoSomethingAmazing();

        // p will be released and cleaned up upon exiting the scope
    }

此示例的(快速而肮脏的)支持代码:

#include <map>
#include <string>
struct cxGrid_s {
    int g1, g2;
    struct DBTableView_s {
        int tv1, tv2;
        struct ViewData_s {
            int vd1, vd2;
            struct Records_s {
                int r1, r2;
                struct FieldByName_s{
                    int fn1, fn2;
                    std::map<std::string, int> value;
                } FieldByName;
            } Records;
        } ViewData;
    } DBTableView;
};

class smartFile
{
public:
    FILE* f{nullptr};
    smartFile() = delete;
    smartFile(std::string fn) { f = fopen(fn.c_str(), "w");    }
    ~smartFile()              { if (f) fclose(f); f = nullptr; }
    FILE* operator*()         { return f;            }
    FILE& operator->()        { return *f;           }
    operator bool() const     { return f != nullptr; }
};

答案 13 :(得分:0)

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

努夫说...

答案 14 :(得分:0)

否,C / C ++中没有with关键字。

但是您可以添加一些预处理器代码:

/* 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->...
    ...
}

简化的未重载定义(选择一个):

未命名(科林风格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循环总是只有一次通过,编译器会对其进行优化。

答案 15 :(得分:0)

也许你可以:

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

或者创建一个小程序,它将理解C ++中的with语句,并将它们转换为某种形式的有效C ++。

答案 16 :(得分:0)

我可以看到一个'with'实际上有用的实例。

在递归数据结构的方法中,您经常遇到以下情况:

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);
  }
}
像这样的拼写错误导致的错误很难找到。

使用'with'你可以写

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

这可能不会超过为'with'提及的所有其他负面因素,但这只是一个有趣的信息......

答案 17 :(得分:0)

以下方法依赖于Boost。如果您的编译器支持C ++ 0x auto,那么您可以使用它并摆脱Boost依赖。

免责声明:请不要在任何必须由其他人维护或阅读的代码中执行此操作(或者甚至在几个月内由您自己维护):

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

答案 18 :(得分:-1)

执行此操作的简单方法如下

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,在没有人把我带到清洁工之前就把它报废了。在更大的程序中,这是一个如何对某物进行可靠计数的示例。