【问题标题】:how to typdef an enum of one namespace inside another and use ist c++ [duplicate]如何在另一个命名空间中键入一个命名空间的枚举并使用ist c ++ [重复]
【发布时间】:2011-09-26 13:45:09
【问题描述】:

可能重复:
How do you import an enum into a different namespace in C++?

如何解决以下枚举命名空间问题?

namespace A {
    typedef enum ABar { a, b };

    void foo( ABar xx ) {}
}

namespace B {
    typedef enum A::ABar BBar;

        void foo( BBar xx ) { A::foo( xx ); } 
}

int main() {
    B::foo( B::a ); // 'a' : is not a member of 'B'
                    // 'a' : undeclared identifier
}

【问题讨论】:

    标签: c++ enums namespaces


    【解决方案1】:

    你不能 typedef 一个枚举。你可以使用它:

    namespace B {
       using A::ABar;
    }
    

    编辑

    这是修改后的示例,可以正常工作:

    namespace A {
        enum ABar { a, b };
    
        void foo( ABar xx ) {}
    }
    namespace B {
        using A::ABar;        // 'ABar' : is injected into namespace 'B'
        using A::a;           // 'a' : is injected into namespace 'B'
    
            void foo( ABar xx ) { A::foo( xx ); }
    }
    int main() {
        B::foo( B::a );
    }
    

    但是,正如 CygnusX1 和 David 指出的那样,以上内容正在污染命名空间 B,最好这样做:

    namespace A {
        enum ABar { a, b };
    
        void foo( ABar xx ) {}
    }
    namespace B {
            void foo( A::ABar xx ) { A::foo( xx ); }
    }
    int main() {
        B::foo( A::a );
    }
    

    还有第三个选项,对它进行类型定义,但要正确:

    namespace B {
        typedef A::ABar BBar;
    
            void foo( BBar xx ) { A::foo( xx ); } 
    }
    

    但你仍然不能这样做:

    B::foo( B::a ); // 'a' : is not a member of 'B'
                    // 'a' : undeclared identifier
    

    因为 BBar 只是 A::ABar 的别名。

    【讨论】:

    • 对不起,我更改了示例,因此它代表了我真正的问题...
    • 你真的试过了吗?我最初的猜测是这样,但这不起作用。
    • 问题是我需要定义一个自己的枚举,它反映了另一个枚举...
    • @David 现在我做到了。添加的示例编译。
    • You can not typedef an enum”真的是真的吗?其他答案以及我自己对typedef X A::ABar; 的实验似乎暗示它是有效的。事实上,据我了解,您可以使用 using 进行别名处理的任何事情都不是您可以使用 typedef 进行的模板别名。
    【解决方案2】:

    问题在于枚举的声明不仅创建了类型,而且还声明了具有给定值的枚举标识符。当您执行 typedef 时,您只是为该类型创建了一个本地别名,但这些值不会被带到新的命名空间。也就是说,编译器将看到B::BBar,它会通过typedef 知道您指的是A::ABar。但是在处理B::a 时,B 命名空间中没有任何内容引用它。

    为此,您还必须将ab 带入新命名空间,这不是由typedef 完成的,因为它们不是类型。无论如何,它是可实现的,例如:

    namespace A {
       enum ABar {
           a, b
       };
    }
    namespace B {
       typedef ::A::ABar BBar;
       using ::A::a;
       using ::A::b;
    }
    

    我不建议这样做,因为它会很快成为维护问题(您必须记住,每次更改原始名称空间时都要更新两个名称空间。

    至于如何处理这个问题,@CygnusX1 提出的解决方法实际上是一个不错的选择,如果您使用的是 C++0x 编译器,该语言允许使用类似的习惯用法,因为它允许访问枚举值通过枚举类型:

    namespace A {
       enum ABar { a,b };
    }
    namespace B {
       typedef A::ABar BBar;
    }
    int main() {
       std::cout << B::BBar::a << std::endl; // extra enum qualification
    }
    

    【讨论】:

    • 好的,谢谢。这对我有很大帮助。可怜的是,vc 9 与 C++0x 不兼容,因为这对我来说似乎是最好的解决方案。但 Cygnus 解决该问题的方式也适用于我。
    【解决方案3】:

    当您 typedef 一个类型时,您不会导入该命名空间中定义的符号。所以虽然你可以写:

    int main() {
        B::BBar enumVariable=A::a;
    }
    

    您无法访问B::a,因为此符号不存在。

    一个部分的解决方法,在我看来,一种使代码更干净的方法,虽然写的时间也更长,是将每个枚举打包到自己的结构中,例如:

    struct ABar {
        enum Type {a, b};
    };
    
    typedef ABar BBar;
    
    int main() {
        ABar::Type var=ABar::a;
        BBar::Type var2=BBar::a;
    }
    

    如果您仍然需要它,您将能够将 ABar 打包到一个命名空间中,并且通常也可以在另一个命名空间中进行 typedef。

    【讨论】:

    • 我看到了问题.. 将枚举打包到自己的类中是没有选择的,因为它是一个 boost 枚举;-)
    • boost::date_time::weekdays/months_of_year 和 boost::date_time::nth_kday_of_month::week_num
    • 我从来没有真正意识到命名空间的这个问题,但我仍然养成了将每个枚举包装在一个结构中的习惯。在我看来,它看起来比通常的枚举值前缀要干净得多,并且必须编写 ABar::Type 而不是 ABar 是一个很小的代价。所以+1(即使它不能解决OP的问题:))。
    • @DrFroid:你考虑过命名空间别名吗? namespace bdt = boost::date_time;, bdt::weekdays wd = bdt::monday;
    猜你喜欢
    • 2016-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-05
    • 2021-11-10
    • 1970-01-01
    • 2012-05-27
    • 2019-07-22
    相关资源
    最近更新 更多