【问题标题】:Detecting namespace in c++在 C++ 中检测命名空间
【发布时间】:2012-09-13 15:52:13
【问题描述】:

是否有可能在给定的代码点检测您是否在命名空间中?特别是,如果文件被包含在全局命名空间中,我想包含一个警告。

【问题讨论】:

  • 文件可以只包含在特定的命名空间中,还是包含在任何命名空间中?
  • @LuchianGrigore 我将它包含在不同的命名空间中,以便在其中执行一些 typedef,如果文件在全局命名空间中生成这些 typedef,我想要一个警告。

标签: c++ namespaces language-lawyer


【解决方案1】:

如果标头不包含在全局命名空间中,我可以给你一个提示,它会生成编译错误。如果我知道 C++ 构造肯定会生成编译器警告(除了#warning),那么它可以用来代替编译错误。

把你的标题:

template <class A, class B>
struct AreSame { enum { VALUE = -1 }; };
template <class A>
struct AreSame<A,A> { enum { VALUE = 1 }; };

struct TestGlobalNamespace
{
   int test_namespace[AreSame<TestGlobalNamespace, ::TestGlobalNamespace>::VALUE];
};

当您的标头包含在某个命名空间中时,您会收到错误消息。

就像这个例子:

namespace Some {

struct TestGlobalNamespace
{
   int test_namespace[AreSame<TestGlobalNamespace, ::TestGlobalNamespace>::VALUE];
};

}

你会得到:

prog.cpp:17: error: size of array ‘test_namespace’ is negative

[更新]

但更可能出现这种错误:

prog.cpp:17: error: ‘::TestGlobalNamespace’ has not been declared
prog.cpp:17: error: template argument 2 is invalid

无论如何 - 没有人敢将您的标头包含在全局以外的命名空间中。

【讨论】:

  • 在我写完这篇文章后,我意识到你想要相反的,当文件在全局命名空间中时发出警告。然后反其道而行之。创建 AreDifferent 模板,你会得到相反的结果。如果你想以这种方式给我留言。
  • 我意识到刚刚在我的答案中添加了新的错误集的可能性更大。如果您希望您的标头仅包含在 Some 命名空间中 - 只需使用 Some::TestSomeNamespace
  • 这对我不起作用...我需要一个 static_assert 在不在全局命名空间中时触发。不会出现编译错误:/.
  • @CarloWood 你试过static_assert(AreSame&lt;TestGlobalNamespace, ::TestGlobalNamespace&gt;::VALUE== 1);` 吗?
  • @PiotrNycz 如果您在随机命名空间中尝试这样做,则必须在该命名空间中定义 TestGlobalNamespace(或者它会说它们当然是相同的)。最后我设法想出了一个宏,当在全局命名空间之外使用时会触发一个断言,但最后删除了它,因为我选择了不同的路线。
【解决方案2】:

良好的做法是在全局命名空间中包含 all 标头。在文件开头打开所有需要的命名空间并在结束前关闭它们。另一种方式不可避免地会导致一堆问题。

** 评论扩展 **

为防止意外包含,您可以执行以下操作:

In header:
#ifndef INTERNAL_INCLUDE
#error ...
#endif

When used:
#define INTERNAL_INCLUDE
#include "internal.h"
#undef INTERNAL_INCLUDE

【讨论】:

  • 不同意。这条规则有例外。例如在boost.org/doc/libs/1_51_0/boost/smart_ptr/shared_ptr.hpp 中有以下包括// implicit conversion to "bool" #include &lt;boost/smart_ptr/detail/operator_bool.hpp&gt;
  • 在我的例子中,我使用一个文件来声明一些我想限制在命名空间中的 typedef,然后将这个文件包含在一些不同的命名空间中。但是,不管这是否是一个好主意,知道我的问题的答案会很有趣。我会标记我的问题语言律师。
  • 我明白了,boost 开发人员以类似的方式使用它。所以,如果你想防止头文件被无意中包含,我希望你添加一个预处理条件:#ifndef _SOME_VAR_ #error bad include #endif
【解决方案3】:

您可以这样做,但需要第二个标头,在第一个标头之前包含在全局命名空间中。

// stuff_guard.h - include from global namespace to guard stuff.h
#ifndef STUFF_GUARD_H
#define STUFF_GUARD_H
typedef char stuff_guard[1];
#endif

// stuff.h - must be included from non-global namespace, after stuff_guard.h
// No include guard - may be included multiple times, in different namespaces.

#ifndef STUFF_GUARD_H
#error stuff_guard.h must be included before stuff.h
#endif

typedef char stuff_guard[2];

static_assert(sizeof (stuff_guard) != sizeof (::stuff_guard), 
    "stuff.h must not be included from the global namespace");

// Put your stuff here

如果您违反这两个规则中的任何一个,这将给出相当友好的错误消息,如果您从非全局命名空间中包含 stuff_guard.h,则会给出不太友好的错误。

如果您使用旧的编译器并且static_assert 不可用,那么您可以使用BOOST_STATIC_ASSERTroll your own

【讨论】:

    猜你喜欢
    • 2013-03-31
    • 2017-10-03
    • 2015-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-23
    • 2019-04-17
    • 1970-01-01
    相关资源
    最近更新 更多