with
关键字可用于快速访问记录的字段。
有谁知道C ++是否有类似的东西?
例: 我有一个包含许多字段的指针,我不想这样输入:
if (pointer->field1) && (pointer->field2) && ... (pointer->fieldn)
我真正想要的是C ++中的这样的东西:
with (pointer)
{
if (field1) && (field2) && .......(fieldn)
}
答案 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)
答案 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,在没有人把我带到清洁工之前就把它报废了。在更大的程序中,这是一个如何对某物进行可靠计数的示例。