with
关键字在 Pascal 中可以用来快速访问记录的字段。
有人知道C++中是否有类似的东西吗?
例如: 我有一个指针,它有很多字段,我不想像这样输入:
if (pointer->field1) && (pointer->field2) && ... (pointer->fieldn)
我真正想要的是C++中类似这样的东西:
with (pointer)
{
if (field1) && (field2) && .......(fieldn)
}
with
关键字在 Pascal 中可以用来快速访问记录的字段。
有人知道C++中是否有类似的东西吗?
例如: 我有一个指针,它有很多字段,我不想像这样输入:
if (pointer->field1) && (pointer->field2) && ... (pointer->fieldn)
我真正想要的是C++中类似这样的东西:
with (pointer)
{
if (field1) && (field2) && .......(fieldn)
}
也许你最接近的方法就是这样:(这只是一个学术练习。当然,你不能在这些人工 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;
if(auto a=foo();true){/**/}
- somebody4没有这样的关键字。
我喜欢使用:
#define BEGIN_WITH(x) { \
auto &_ = x;
#define END_WITH() }
例子:
BEGIN_WITH(MyStructABC)
_.a = 1;
_.b = 2;
_.c = 3;
END_WITH()
在C++中,你可以将代码放入被指针
引用的类的方法中。这样你就可以直接引用成员而不使用指针。将其设为内联
函数,你就能够得到想要的结果。
inline
” 是什么意思?你能在另一个函数内部声明这个方法吗?这很奇怪... - Dacavwith
中使用的类中添加一个方法。将其设置为 inline
允许它进入头文件,但除此之外没有其他的效果。这样的一个方法必须在它的原始类中声明,并在任何其他函数之外定义。我下面的答案有一个解决这两个问题的方法。 - PotatoswattercxGrid.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
更清晰。
T&
或 T const&
变量来保存对长表达式的引用(在 T&
情况下,必须是一个适当的左值)。为了使其视觉上更加突出,我通常将变量命名为 _
。 - j_random_hackerC++没有类似的特性。而且许多人认为Pascal中的"WITH"是一个问题,因为它可能会使代码模糊和难以阅读,例如很难知道field1是指针的成员还是局部变量或其他什么东西。Pascal还允许多个with变量,例如"With Var1,Var2",这使得情况更加复杂。
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->...
...
}
简化的非重载定义(选择一个):
未命名(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
循环总是只有一次遍历,并且将被编译器优化掉。with (OBJECT) {CODE}
C++中不存在这种东西。
你可以将代码放在对象的方法中,但这并不总是理想的。
使用C++11,您可以通过为对象创建短名称别名来实现相当接近。
例如,在问题中给出的代码将如下所示:
{
auto &_ = *pointer;
if (_.field1 && ... && _.fieldn) {...}
}
如果您经常使用某个字段,可以直接使用别名来简化操作:
周围的花括号用于限制别名_
的可见性。
auto &field = pointer->field;
// Even shorter alias:
auto &_ = pointer->busy_field;
with
关键字,它实际上做的事情基本相同;我没想到它的渊源可以追溯到 Pascal (!)。 - Ben Zotto