"using std::begin;" 是个好习惯吗?

Is "using std::begin;" a good practice?

正如我所读到的,begin(some_vector)some_vector.begin() 更标准,因为它支持数组...而且据我所知,使用 using keyword 并不是真正可取的行为.但是,我也看到很多代码只包含这两个 usings:

using std::begin;
using std::end;

这是好事还是坏事?尤其是需要很多 beginend 的时候?

视情况而定。强烈建议不要在头文件中使用声明(以及更多的使用指令)。但是,如果在函数体内多次使用来自另一个命名空间的一个或多个函数,则 using 声明/指令(放在函数体内,因此仅限于其范围)可以使代码更具可读性。

这对 ADL 帮助很有帮助。类似于:

template<typename T, typename F>
void apply(T& v, const F& f)
{
   using std::begin;
   using std::end;
   std::for_each(begin(v), end(v), f);
}

因此,我们可以用具有 begin/end 函数和经典 C 数组的类型调用 apply

在其他情况下,在源文件中使用 using 指令实际上是可以的,在小范围内等等,但是在头文件中使用是不好的。

Is that considered good or bad practice?

这在很大程度上取决于上下文;我认为答案同样适用于通过 using 引入名称这一更普遍的问题。限制使用范围 using 使得代码更具可读性(例如函数级范围);按需使用,谨慎使用

这里有一个特别有趣的案例围绕 ADL。

template <class Container>
void func(Container& c)
{
  std::for_each(begin(c), end(c), /* some functor*/);
}

ADL 已经在发挥作用,因为如果容器来自 std 命名空间,则会找到 std::beginstd::end。如果容器来自自定义命名空间,则可以在该命名空间中找到 beginend 函数(对于本次讨论,我假设容器提供商也提供了这些)。

如果容器是一个普通的 C 风格数组,数组形式 std::begin(T (&array)[N]) 将不会被找到,因为 C 风格数组不是 std 命名空间。这里引入一个using std::begin可以让代码用于数组和容器

template <class Container>
void func(Container& c)
{
  using std::begin; // if c is an array, the function will still compile
  using std::end;
  std::for_each(begin(c), end(c), /* some functor*/);
}
// ...
int a[100];
func(a); // works as expected

Demo.

As I have read, begin(some_vector) is more standard than some_vector.begin() because of array support

不是"more standard",都是100%标准。它更通用,因为它适用于数组,但拥有一个对象却不知道它是数组还是容器类型的情况实际上并不常见。如果您知道某些东西是数组,则使用 std::begin(a) 但如果您知道某些东西不是数组,那么使用也适用于数组的形式没有任何优势。如果您在通用上下文中可能有任何一种情况,那么 std::begin 适用于这两种情况。

the use of using keyword is not really desirable behavior.

这是有争议的。在大多数情况下(即 using namespace foo)有很好的理由避免使用指令,但相同的论点不适用于引入单个名称的 using 声明(即 using foo::bar)。例如,推荐使用 std::swap 的方法是通过 using std::swap,因此 using 关键字通常是不受欢迎的,这当然是不正确的。

Is that considered good or bad practice? Especially when many begin and end are needed?

我会说总的来说这是个坏主意。正如其他答案所解释的那样,它允许 ADL 找到 beginend,但这不一定是一件好事。为 beginend 启用 ADL 可能会导致问题,这就是为什么我们在最后一分钟将基于范围的 for 更改为 而不是 使用 using std::begin; using std::end; 为避免歧义,请参阅 N3257 了解详细信息。