【问题标题】:How to avoid littering header files with std::如何避免使用 std:: 乱扔头文件
【发布时间】:2016-02-26 13:13:07
【问题描述】:

我喜欢完全在头文件中实现类,但我不喜欢在我的代码中使用std::

我认为在头文件中使用using namespace std 会很糟糕,因为这会污染所有下游源文件的命名空间。

所以我经常在头文件中做这样的事情:

class foo {
    using std::vector;
    // in this code I don't need to qualify vector with std::
}

但这似乎不适用于某些事情,例如std::unique_ptrstd::invalid_argumentstd::move

有什么办法可以满足我的需求吗?

【问题讨论】:

  • 为什么明确说明你的东西来自哪个命名空间是一件坏事?我几乎用明确的std:: 编写了所有代码,因为它清楚地表明了什么是什么。
  • 它是如何“不工作”的?
  • 当您忘记自己编写代码时,您将阅读代码。明确你的意思是很好的。最好的补救办法是接受std::。您现在可能不喜欢它,但您未来的自己会感谢您对清晰度如此体贴。
  • 哇,如果 std:: 惹恼了你,boost:: 会让你发疯的 O.o
  • 是的,在函数范围内添加它会使它变得更没用,因为大多数时候,您只需要几次该名称,因此您添加另一行 10-15 个字符避免输入 10....

标签: c++ namespaces


【解决方案1】:

使用std:: 没有任何问题。事实上,我发现我的自读代码是由其他人编写的,当我看到 stack stk; 之类的东西时,我会怀疑 stack 是否是标准的。因此,我建议您使用它,因为尽管您再输入 5 个字符,但它会使您的代码对其他编码人员更具可读性。

现在至于为什么您尝试过的方法不起作用。不是因为 C++ 不允许这样做。根据草案标准7.3.4/p1 使用指令[namespace.udir]Emphasis Mine):

using-directive 不应出现在类范围内,但可以出现在命名空间范围或块范围内。 [注:查找时 使用指令中的命名空间名称,只有命名空间名称是 考虑,见 3.4.6。 — 尾注] 可选 属性说明符序列属于使用指令。

上面的引用证明了你为什么不能这样做:

class Foo {
  using namespace std;
};

你不能这样做:

class Foo {
  using std::vector;
};

因为std::vector 是一个模板类(即,它需要<T>)。

同样来自标准草案7.3.3/p5的使用声明[namespace.udecl]:

using-declaration 不得命名模板 ID。

禁止你这样做:

class Foo {
  using std::vector<int>;
};

如果这让您如此“困扰”您,您会怎么做。将所有代码放入命名空间并将using namespace std; 拖到那里:

namespace mine {
  using namespace std;

  struct foo {
    unique_ptr<int> ptr;
  };
}

但是,当您执行 using namespace mine; 时,这不会让您免于拖动 std 命名空间。

另一个选项如果你的编译器支持 C++11,创建一个模板别名:

struct Foo {
  template<typename T>
  using unique_ptr = std::unique_ptr<T>;
  unique_ptr<int> ptr;
};

【讨论】:

  • 请注意,OP 抱怨 using declarations 不起作用(例如 using std::vector;。值得检查是否适用与使用指令相同的规则 (using namespace blah;)
  • @juanchopanza 非常感谢,我希望现在一切都得到澄清。
【解决方案2】:

我的建议仍然是养成随时随地使用std:: 的习惯。写出来是好事,不是坏事。

我将所有内容都“放在一个文件中”,但这应该作为一个标题或一个文件解决方案:

#include <memory>
#include <vector>
#include <stdexcept>

using std::vector;
using std::invalid_argument;
using std::unique_ptr;

class foo
{

public:
    foo(int x)
    {
        if (x > 100) throw invalid_argument("too big");
        iv.push_back(x);
    }

private:
    vector<int> iv;
    unique_ptr<int> ip;
};

int main()
{
    foo bar(32);
}

类中的using 允许您以不同的方式编写typedef(有人说“更具可读性”):

using vector_int = std::vector<int>;

并引用(例如)不同类的构造函数:

class BasicTypeDecl : public TypeDecl
{
public:
    using TypeDecl::TypeDecl;
    ...
};

有了这些“知识”,我们可以想出:

#include <memory>
#include <vector>
#include <stdexcept>


class foo
{

public:
    using intvec=std::vector<int>;
    using intup = std::unique_ptr<int>;

    foo(int x)
        {
            using std::invalid_argument;
            if (x > 100) throw invalid_argument("too big");
            iv.push_back(x);
        }

private:
    intvec iv;
    intup ip;
};

int main()
{
    foo bar(32);
}

这有std::invalid_argument,但其他类型使用using 语句的别名,如果您多次使用相同的类型,这可能是有道理的(实际上,您也可以全局使用它,以为多次使用的类型创建通用名称)

【讨论】:

    猜你喜欢
    • 2012-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-07
    • 2017-12-02
    • 2021-04-13
    相关资源
    最近更新 更多