【问题标题】:Using fully qualified name for std namespace in C++在 C++ 中为 std 命名空间使用完全限定名称
【发布时间】:2019-07-10 22:34:27
【问题描述】:

如果 C++ 中的名称不是完全限定的,例如std::cout,可能会导致意外错误,如https://en.cppreference.com/w/cpp/language/qualified_lookup 中提到的。但是使用::std 命名空间的完全限定名称,例如。 ::std::cout,非常罕见,我注意到了。

是否有任何理由不使用 ::std 命名空间的完全限定名称?

那么对于自己创建的命名空间使用完全限定名称呢?这是个好主意吗?

【问题讨论】:

  • 那是因为任何创建名为std 的嵌套类或命名空间的人都应该在他们提交的那一刻被护送出校园。所以在实践中这不是问题。
  • @n.m.优秀 !因此,我已经将我的答案的措辞从“没有人会调用一个标准类”更新为“没有人会敢于调用一个类标准”;-)
  • @n.m.这难道不值得更多的阐述进化来回答吗?为什么只是简短的评论?
  • @Red.Wave 这只是个玩笑。
  • @n.m.它更多。因为它有一个点,并且实际上击中了中心点。

标签: c++ namespaces naming name-lookup scope-resolution


【解决方案1】:

你是完全正确的,如果有一个命名空间yyyy 和一个类yyyy 都在同一范围内可见,那么yyyy::xxx 可能是模棱两可的。在这种情况下,只有完整的资格 ::yyyy::xxx 才能解决歧义。您的链接示例非常清楚:

// from cppreference.com
#include <iostream>
int main() {
  struct std{};
  std::cout << "fail\n"; // Error: unqualified lookup for 'std' finds the struct
  ::std::cout << "ok\n"; // OK: ::std finds the namespace std
}

但在实践中,很难在顶层创建一个冲突的std,因为标准库中的大多数包含都会使其失败:

#include <iostream>

struct std {      // OUCH: error: ‘struct std’ redeclared as different kind of symbol
    int hello;  
}; 

这意味着要创建冲突,您需要定义本地类或在另一个命名空间中引入using 子句。此外,没有人会(敢)打电话给班级std

最后,在实践中,::yyyy::xxx 阅读起来不太方便。这一切都解释了为什么你不会经常找到它。

补充说明

问题不在于众所周知的std,而在于您自己的命名空间和第三方库。在这种情况下,namespace alias 将是 :::yyyy 的更好替代品来消除歧义:

namespace foo {
    void printf() { }
}
int main() {
    foo::printf();          // ok, namespace is chose because no ambiguity
    struct foo {/*...*/ };  // creates ambiguity
    //foo::printf();        // error because struct foo is chosen by name lookup
    ::foo::printf();        // ok, but not if you  decide to move the code to be nested in another namespace
    namespace  mylib = foo ;   // or ::foo (see discussion below)
    mylib::printf();        // full flexibility :-)
}

它的优点是更高的灵活性。例如,假设您将移动代码以将其嵌套在封闭的命名空间中。使用命名空间别名,您的代码可以继续按原样工作(在最坏的情况下,只需对别名定义进行细微调整)。使用全局范围解析,您必须更改将使用全局命名空间::foo 的所有语句。

【讨论】:

  • namspace mycrazyspace{ namespace std{ /* 我的精神病患者的东西*/};};没有人敢这样做。但我可能已经疯了!!!!? 而且工具链不会发现任何错误。
  • @Red.Wave :-D 你成就了我的一天!你当然可以这样做!您甚至可以在需要消除歧义时使用全局范围解析运算符:至少我们会有人会喜欢该语言功能 ;-) 开个玩笑,此功能也适用于 std 以外的其他命名空间,其中更容易发生冲突。而且我猜它主要用于创建不那么模棱两可的别名
  • 我不想打扰,但我的意思是提供的答案需要修改。
【解决方案2】:

为了保持大代码或更好的可读性或名称冲突,C++ 提供了命名空间“声明性区域”。 命名空间定义只能出现在全局范围内,或嵌套在另一个命名空间中。

#Sample Code
#include <iostream>
int main() 
{
      struct std{};
      std::cout << "fail\n"; // Error: unqualified lookup for 'std' finds the struct
      ::std::cout << "ok\n"; // OK: ::std finds the namespace std
}

在上面的代码中,编译器在 struct std 中寻找 cout,但是当你使用 ::std::cout 时,它会在下一行寻找 cout 在全局定义的 std 类中。

解决方案:

#include <iostream>
//using namespace std; // using keyword allows you to import an entire namespace at once. 

namespace test
{
    void cout(std::string str)
    {
       ::std::cout<<str; 
    }
}

int main() 
{
    cout("Hello");//'cout' was not declared in this scope
    ::test::cout("Helloo ") ;
    ::std::cout<<"it is also ok\n";
}

或者这样使用,只是为了更好的可读性

##
using namespace test;
int main() 
{
    cout("Hello");//'cout' was not declared in this scope
    cout("Helloo ") ;
    ::std::cout<<"it is also ok\n";
}

【讨论】:

  • 有趣!您还可以定义命名空间别名namespace mystd = ::std;。在这种情况下,您可以参考mystd::cout。如果稍后您希望使用自己的替代库,您可以将别名更改为namespace mystd = test;,而无需更改使用mystd 的其余代码。
猜你喜欢
  • 1970-01-01
  • 2017-08-09
  • 2013-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-08
相关资源
最近更新 更多