4

Is this even possible? I would like to write a macro that makes it easier to use some of my classes functionality.

Lets say I have 2 member functions in my class, setup() and cleanup(), where setup() sets up parameters for some operation that needs to be executed in its own scope, and cleanup() preforms cleanup (similar to a constructor and destructor concept).

Currently, I do this:

myClassInstance.setup(); //call the setup function
{ //start scope
    //CREATE LOCAL VARS
    //DO STUFF IN THIS SCOPE
    myClassInstance.cleanup(); //cleanup
} //end scope, destroy locals

But would like to do something like this instead:

NEWSCOPE(myClassInstance) //calls setup()
{
    //CREATE LOCAL VARS
    //DO STUFF IN THIS SCOPE
} // calls cleanup() and destroys locals

My thought was to write a macro class that can be instantiated when the macro is used and setup() and cleanup() could be implemented in the constructor/destructor... or something like that...

Is this the right way to think about this or is there another way to write a macro that can essentially wrap around code written by the user?

* EDIT * I fixed the naming convention as the function names were causing come confusion.

4

4 回答 4

3

要创建新范围,只需使用匿名块。

{ 
    Obj obj;
    /* 
    teh codez
    */
}//obj is deallocated

所以你不需要宏

听起来也像您startScopeendScope实际上应该是构造函数和析构函数,但是如果不知道它们实际上做什么就很难知道

更新:我试图给你一个答案,但我只会咆哮。

类似于构造函数和析构函数的概念

对我来说,这听起来像是构造函数和析构函数,当你让构造函数和析构函数进行设置和清理时,这些操作将使用 RAII 自然且可读地执行。

另一件事,您说您的第一个解决方案(我有点意外地回馈给您)正在工作,为什么需要在 C 宏中使用宏来模拟 C++ 提供的功能(如模板和对象)。对于几乎所有情况,尤其是在 C++11 中,宏只会让事情变得更糟,更难调试,在你的情况下,看起来你在执行宏时实际上必须输入更多内容?

我的建议是重新考虑为什么你需要一个宏以及为什么setup不能cleanup成为构造函数和析构函数。

于 2013-08-14T23:25:02.347 回答
2

您可以像使用 RAII 获得互斥锁一样对待它。像这样的东西:

class MyClassScopeBlock
{
  public:
    MyClassScopeBlock( MyClass & c )
        : obj(c)
    {
        obj.startScope();
    }

    ~MyClassScopeBlock()
    {
        obj.endScope();
    }

  private:
    MyClass & obj;
};

然后将其实例化为范围块内的局部变量:

{
    MyClassScopeBlock block( myClassInstance );
    //CREATE LOCAL VARS
    //DO STUFF IN THIS SCOPE
}

如果你真的想要,你可以为它定义一个宏,在范围块内使用:

#define NEWSCOPE(inst) MyClassScopeBlock block(inst)

就个人而言,我更喜欢尽可能远离宏。

于 2013-08-14T23:29:20.153 回答
1

在看到 BOOST_FOREACH 宏后,我花了几个小时试图弄清楚如何使宏控制成为范围。在弄清楚它的过程中,我遇到了这个问题,希望它能够回答!但是,不完全是。因此,我通读了 BOOST_FOREACH 的所有代码和 BOOST_FOREACH的原始设计。然后我觉得有点愚蠢......宏基本上将代码直接插入到它所在的位置。这意味着我们可以有一个宏:

#define LOOP_3() \
    for(int i = 0; i < 3; ++i)

现在,让我们测试一下吧!

LOOP_3() std::cout << "Hello World!" << std::endl;
/* === Output ===
Hello World!
Hello World!
Hello World!
*/

耶!但是,这有什么用呢?那么,在循环结束时会发生什么i?调用了析构函数 which fori并不太花哨,但想法就在那里。

我们现在只需要一个类来处理这个问题:

class SCOPE_CONTROL {
public:
    SCOPE_CONTROL(): run(1) { std::cout << "Starting Scope!" << std::endl; }
    ~SCOPE_CONTROL() { std::cout << "Ending Scope!" << std::endl; }
    bool run;
}

让我们使用那个吸盘!

#define NEWSCOPE() \
    for(SCOPE_CONTROL sc = SCOPE_CONTROL(); sc.run; sc.run = 0)

...
NEWSCOPE()
    std::cout << "    In the Body!" << std::endl;
std::cout << "Not in body..." << std::endl;
...

/* === Output ===
Starting Scope!
    In the Body!
Ending Scope!
Not in body...
*/

要使用setupcleanup功能,只需稍作改动!

class SCOPE_CONTROL {
public:
    SCOPE_CONTROL(MyClass myClassInstance): control(myClassInstance), run(1) { 
        control.setup();
    }
    ~SCOPE_CONTROL() { control.cleanup(); }
    bool run;
    MyClass & control;
}
#define NEWSCOPE(control) \
    for(SCOPE_CONTROL sc = SCOPE_CONTROL(control); sc.run; sc.run = 0)

...
NEWSCOPE(myClassInstance)
{
    // CREATE LOCAL VARS
    // DO STUFF IN THIS SCOPE
}   // end scope, destroy locals
...

为了让它更好地使用ENCODED_TYPE(如何在 BOOST_FOREACH 的设计中非常简单!)允许SCOPE_CONTROL成为模板类型。

于 2015-11-05T18:15:32.123 回答
0

将整个范围放在宏替换中的更好选择是使用类似finallyblock的东西。我已经成功地用这些宏封装了链接的解决方案:

#define FINALLY_NAMED( NAME, ... ) auto && NAME = \
        util::finally( [&]() noexcept { __VA_ARGS__ } );
#define FINALLY( ... ) CPLUS_FINALLY_NAMED( guard, __VA_ARGS__ )
#define DO_FINALLY static_cast< void >( guard );

用法:

{
    myClassInstance.setup(); //call the setup function
    FINALLY ( myClassInstance.cleanup(); ) //call the cleanup function before exit

    // do something

    DO_FINALLY // Explicitly note that cleanup happens here. (Only a note.)
}

这是异常安全的,cleanup当且仅当setup成功完成时才执行,就像构造函数/析构函数对一样。但是cleanup一定不能抛出异常。


但是如果你想用老式的方式来做……</p>

您可以使用可变参数宏将整个范围包含在宏中:

#define NEWSCOPE( INSTANCE, ... ) { \
    (INSTANCE).setup(); /* call the setup function */ \
    { __VA_ARGS__ } /* paste teh codez here */ \
    (INSTANCE).cleanup(); /* call the cleanup function */

我建议不要放在cleanup内部范围内,因为范围的目的是包含声明和名称,但您想使用INSTANCE外部范围的名称。

用法:

NEWSCOPE ( myClassInstance,
    // Do stuff.
    // Multiple declarations, anything can go here as if inside braces.
    // (But no #define directives. Down, boy.)
)
于 2013-08-15T00:14:08.300 回答