返回

下面简称郑智允为ZZY,冯建鑫为FJX

1(FROM ZZY)

#include <iostream>

int main()
{
    endl(std::cout);
    return 0;
}

猜这段代码能否通过编译。

如果不能,是因为什么编译错误?

如果能,请解释原因。

2(FROM FJX)

能。

首先,endl是一个操作符,由于他在<<后,所以它应该是一个参数。其实不然,它是一个函数,内部函数就说明了这一点:

ostream& ostream::operator << ( ostream& (*op) (ostream&))
{
     // call the function passed as parameter with this stream   as the argument
      return (*op) (*this);
 }
 std::ostream& std::endl (std::ostream& strm)
{
    // write newline
     strm.put('\n');
     // flush the output buffer
     strm.flush();
     // return strm to allow chaining
     return strm;
 }

很明显,endl是一个函数,再由于你没有明确的命名空间,所以参数你填了std::cout。(如果有using namespace std,那就填cout)

3(FROM ZZY)

问题出现在这里,为什么不是 std::endl 而仅是 endl 就可以编译通过呢?

4(FROM FJX)

endl是一个函数,我都说了……

5(FROM ZZY)

函数也需要限定引用啊?

6(FROM ZZY)

endl 声明在 标准命名空间中,这里凭什么就可以不指明是标准命名空间?

7(FROM ZZY)

照你所说,以下的 std::next 也是一个函数,为什么不加 std:: 限定引用反而会编译失败?

#include <algorithm>
#include <iostream>

int main()
{
    int a[3] = {1, 2, 3};
    //std::cout << *next(a, 1);  // 编译不通过
    std::cout << *std::next(a, 1);
    return 0;
}

8(FROM FJX)

endl确实在std中,但他的函数在内部库中,跟标准命名空间没有一毛钱关系!

9(FROM ZZY)

endl 就是一个函数。

10(FROM ZZY)

而你所说的内部库,其实是头文件。根据标准,std::endl 必须声明在且仅在 标准命名空间 中。

11(FROM ZZY)

换言之,你无法在 标准命名空间 以外的任何地方找到 C++ 自带的 endl 函数。

12(FROM ZZY)

endl 并没有分成两部分实现。endl 只有一个,在 标准命名空间中。

13(FROM FJX)

#include <algorithm>
#include <iostream>

int main()
{
    int a[3] = {1, 2, 3};
    //std::cout << *next(a, 1);  // 编译不通过
    std::cout << *std::next(a, 1);
    return 0;
}

你说的是*std::next,*next当然不通过

14(FROM ZZY)

如果他的函数在内部库当中,那么如果要让以上代码编译通过,我们一定需要一种方式来得知一个内部库的 endl 的声明,问题就在于你无法找到 endl 除了在标准命名空间以外的第二个声明。

15(FROM FJX)

你没有using namespace std

16(FROM ZZY)

但是如果是这样就可以编译通过了:

#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
    std::vector<int> arr{1, 2, 3};
    std::cout << *next(arr.begin(), 1) << '\n';
    return 0;
}

17(FROM ZZY)

你有应该如何解释这种情况呢?

18(FROM FJX)

所以你要加std::

19(FROM ZZY)

我并没有给 next 加 std::,仅仅是把数组变成了 std::vector 而已。

20(FROM FJX)

你加别的库了,兼容了标准命名空间

21(FROM ZZY)

让我换一种毫无争论的方式来提问吧。

22(FROM ZZY)

见如下代码,假定你已经知道模板等知识:

#include <cstdlib>

#include <iostream>

namespace A
{
    struct S
    {};

    void func(S x)
    {
        exit(0);
    }
}  // namespace A

namespace B
{
    // 调用一个没有实现的函数,编译会出现链接错误 (1)
    template <typename T>
    void func(T x);
}  // namespace B

int main()
{
    using namespace B;
    A::S value;
    func(value);  // 但这里却不会报错,甚至能够运行
    // func(2);  // 如 (1) 处所言,这里会因为找不到定义而编译错误
    return 0;
}

23(FROM ZZY)

注意,我在主函数中 using namespace 的是 B 命名空间。

24(FROM ZZY)

@ 郑智允 你加别的库了,兼容了标准命名空间

或者我全部换成 万能头,之前代码的效果依然不变。

#include <bits/stdc++.h>

int main()
{
    int a[3] = {1, 2, 3};
    //std::cout << *next(a, 1);  // 编译不通过
    std::cout << *std::next(a, 1);
    return 0;
}

#include <bits/stdc++.h>

int main()
{
    std::vector<int> arr{1, 2, 3};
    std::cout << *next(arr.begin(), 1) << '\n';
    return 0;
}

25(FROM ZZY)

帖子不能烂尾,简单收一下尾。

这是由于 C++ 存在一种叫 ADL 的机制,具体见 这里

返回