【问题标题】:How to define a macro that retains its scope after it's been called如何定义在调用后保留其范围的宏
【发布时间】:2010-04-19 15:34:42
【问题描述】:

我正在尝试制作一个宏,以便更轻松地定义属性。

简化的例子,但目前我有这个提供一个公共获取和私有集的属性:

#define propertyRO(xxType, xxName)\
    property xxType xxName\
    {\
        xxType get() {return m___##xxName;}\
        void set(xxType value) {m___##xxName = value;}\
    }\
    private:\
        xxType m___##xxName;\

然后要使用它,您可以这样做:

public ref class Wawawa
{
public:
    int bob;
    propertyRO(String^, MyName);
};

这可能会很好用,但它有缺陷,因为成员是在私有范围内指定的,这意味着在宏之后发生的任何事情也会获得私有范围。例如:

public ref class Wawawa
{
public:
    int bob;
    propertyRO(String^, MyName);
    int fred; //ERROR HERE <- this would be private not public
};

所以如果你忽略这个宏的实际作用,我真正的问题是:有没有什么方法可以在宏中使用private: 关键字,而不影响类的其余部分?

【问题讨论】:

    标签: variables visual-c++ scope c++-cli c-preprocessor


    【解决方案1】:

    在类定义的末尾一起插入您的属性宏调用。 (我同意,这个答案有点蹩脚;))

    【讨论】:

    • 如果您有多个要公开的属性仍然不好...您必须在每个属性之间添加一个public:
    • 这可以通过在 propertyRO 宏的第一行添加“public:\”来解决(无论如何这会更清楚)。可以类似地添加私有属性。
    • 是的。但是我当然想知道是否有更好的方法可以在当前范围内起作用:)
    【解决方案2】:

    我会回答:只是不要这样做。不要使用宏来生成代码。看起来它会节省您的时间和精力,但是您已经发现宏有问题,这对于阅读类声明的人来说肯定不是显而易见的。您可能很快就会发现调试它是一场噩梦,因为调试器只指向宏行,而不是其中的代码。

    IMO,咬紧牙关,把所有的属性全部写出来。

    【讨论】:

    • 调试器在调试时设法将其拾取(如果您将鼠标悬停在 Wawawa 类型的对象上,您可以看到 MyName 和 m___MyName 的当前值)。我确实同意你的观点,但它并不明显。
    • 当然,它会拾取这些,但我的意思是调试器可能将设置器和获取器视为在同一行 - 宏行。因此,如果您尝试进入设置器,调试器只会指向宏。如果您想更改其中一个的设置器,您将不得不手动进行一些丑陋的宏粘贴,这会增加您的维护麻烦,这就是为什么我建议将其完整地写出来。
    • 关于在同一行,我现在明白你在说什么,但我怀疑我是否想进入这个宏。至于维护问题,这就是首先制作这个被遗弃的宏的全部原因 :) 你必须用 C++/CLI 编写的代码量来创建一个带有私有集的属性简直是疯了。
    【解决方案3】:

    我觉得这不可能。

    所以也许一个更好的建议是将宏重命名为publicPropertyRO,这样可以很明显地创建一个公共属性。并将私有成员移动到属性声明之上:

    #define publicPropertyRO(xxType, xxName)\
        private:\
            xxType m___##xxName;\
        public:\
            property xxType xxName\
            {\
                xxType get() {return m___##xxName;}\
                void set(xxType value) {m___##xxName = value;}\
            }\
    

    这将使班级处于public: 状态,我认为这是可以接受的。
    没有真正回答我的问题,但至少这是一个改进。

    【讨论】:

    • 这似乎是最好的选择,但是在“受保护”甚至“私有”区域中使用宏的问题仍然存在。
    【解决方案4】:

    问题的核心是propertyRO宏改变了底层的范围,对吧?问题不在于它本身改变了作用域,而在于它是以隐藏的方式完成的,所以处理这个问题的最佳方法是公开它。

    Demoncodemonkey's suggestion 是将 public 嵌入到函数的名称中(这可能没问题),但另一种方法是将宏后面的范围作为参数。例如

    #define propertyRO(xxType, xxName, xxFollowingScope)\
        property xxType xxName\
        {\
            xxType get() {return m___##xxName;}\
            void set(xxType value) {m___##xxName = value;}\
        }\
        private:\
            xxType m___##xxName;\
        xxFollowingScope:
    

    ...

    public ref class Wawawa
    {
    public:
        int bob;
        propertyRO(String^, MyName, public);
        int fred; // No error here, fred is public
    };
    

    语法和命名不是超级好,但它确保在没有有意识地决定函数之后的范围应该是什么的情况下使用这个宏是不可能的。

    【讨论】:

    • 有趣,我喜欢你的思维方式:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-24
    • 1970-01-01
    相关资源
    最近更新 更多