使用C ++宏创建新范围?

时间:2013-08-14 23:23:20

标签: c++ macros scope

这甚至可能吗?我想写一个宏,这样可以更容易地使用我的一些类功能。

假设我的类中有2个成员函数,setup()和cleanup(),其中setup()为某些需要在自己的作用域中执行的操作设置参数,cleanup()预先清理(类似)构造函数和析构函数概念)。

目前,我这样做:

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

但是想做这样的事情:

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

我的想法是写一个宏类,可以在使用宏时实例化,并且setup()和cleanup()可以在构造函数/析构函数中实现......或类似的东西......

这是考虑这个的正确方法还是有另一种方法来编写一个可以基本上包裹用户编写的代码的宏?

*编辑* 我修复了命名约定,因为函数名称引起了混乱。

4 个答案:

答案 0 :(得分:2)

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

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

所以你不需要宏

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

更新:我试着给你答案,但我只是咆哮。

  

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

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

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

我的建议是重新考虑为什么你需要一个宏,为什么setupcleanup不能是构造函数和析构函数。

答案 1 :(得分: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)

就个人而言,我更愿意尽可能远离宏。

答案 2 :(得分:0)

将整个范围置于宏替换中的更好的替代方法是使用finally block之类的东西。我已成功将链接的解决方案封装在这些宏中:

#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不能抛出异常。


但如果你想以老式的方式做到这一点......

您可以使用variadic宏包含宏中的整个范围:

#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.)
)

答案 3 :(得分:0)

我花了好几个小时试图弄清楚如何在看到BOOST_FOREACH宏之后让宏控制成为一个范围。在搞清楚的过程中,我遇到了这个问题,希望能得到答案!但是,并不完全。因此,我仔细阅读了所有code for the BOOST_FOREACH和原始design for 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会发生什么? 析构函数被调用,i对于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...
*/

让我们使用那个吸盘!

setup

要使用cleanupclass 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

为了更好地使用SCOPE_CONTROL(如何使BOOST_FOREACH的设计非常简单!)允许compile 'com.google.android.gms:play-services-analytics:8.1.0' compile 'com.android.support:appcompat-v7:23.1.0' compile 'com.android.support:design:23.1.0' compile 'com.android.support:cardview-v7:23.1.0' compile 'com.android.support:recyclerview-v7:23.1.0' compile 'com.squareup.picasso:picasso:2.5.2' compile 'de.greenrobot:eventbus:2.4.0' compile 'com.squareup.okhttp:okhttp:2.4.0' compile 'com.squareup.okhttp:okhttp-urlconnection:2.+' compile 'com.adjust.sdk:adjust-android:4.1.2' 成为模板类型。