为什么这段 C++ 代码可以用某些编译器编译,而不能用其他编译器编译?

Why does this C++ code compile with some compilers but not others?

我在做家庭作业时注意到,我笔记本电脑上的编译器比我们预期用于提交的机器上的编译器要宽松得多。我笔记本电脑上的 C++ 编译器是 AppleClang 7.0.2.7000181,提交框上的编译器是 g++ 4.9.2。回想起来不应该编译的代码是:

#include <iostream>

std::tuple<int, int> foo() {
    return std::make_tuple(1, 1);
}

int main() {
    auto pair = foo();
    int x = std::get<0>(pair);
    int y = std::get<1>(pair);
    std::cout << x << "," << y << std::endl;
    return 0;
}

我也有一个CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)
project(foo)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Wall -Werror -Werror=sign-compare")

set(SOURCE_FILES main.cpp)
add_executable(foo ${SOURCE_FILES})

在我的笔记本电脑上,Clang 愉快地编译了这段代码并打印了出来 1,1。没有错误,没有警告,什么都没有。在投稿箱上,我就没那么幸运了

/home/nate/foo/main.cpp: In function 'std::tuple<int, int> foo()':
/home/nate/foo/main.cpp:3:26: error: return type 'class std::tuple<int, int>' is incomplete
 std::tuple<int, int> foo() {
                          ^
/home/nate/foo/main.cpp:4:12: error: 'make_tuple' is not a member of 'std'
     return std::make_tuple(1, 1);
            ^
/home/nate/foo/main.cpp: In function 'int main()':
/home/nate/foo/main.cpp:8:21: error: 'void pair' has incomplete type
     auto pair = foo();
                     ^
/home/nate/foo/main.cpp:9:13: error: 'get' is not a member of 'std'
     int x = std::get<0>(pair);
             ^
/home/nate/foo/main.cpp:10:13: error: 'get' is not a member of 'std'
     int y = std::get<1>(pair);
             ^

这些错误是有道理的,因为我没有包括 tuple header,但我不明白为什么这段代码可以在我的笔记本电脑上编译。这是怎么回事?

允许使用标准 header,但不要求包含其他标准 header。 clang 的 iostream header 可能直接或间接包含 tuple。没有标准机制可以诊断您因此忘记了标准 header。

不同的实现可能会选择在其他 headers 中包含一些 headers。您应该始终包含您使用的 headers。如果你这样做,那么它会用两个编译器编译。 clang 似乎在 <iostream> 中包含 <tuple> 而 gcc 没有。他们被允许以任何一种方式进行,并且您必须确保包含您需要的 headers 。

不同的编译器有不同的header文件。 C++ header 文件与您使用的编译器密切相关。

您可能拥有的是 Clang 的 <iostream> 本身 #include 是元组 header 文件,无论出于何种原因;因此引用 std::tuple 的代码将仅通过 #includeing <iostream> header.

就可以愉快地编译

当然,这取决于您的编译器的特定行为。

不同的编译器有不同的header文件。 C++ 标准不禁止一个 header 文件自动包含另一个文件;但是为了使用特定的 class、模板或其他资源,确保此 class、模板或其他资源可供您的代码引用的唯一方法是明确包含其 header 个文件。

代码由特定编译器编译的事实并不一定意味着您的代码是正确的。正如 documentation for std::tuple 中所述,它需要包含 header <tuple>,违反这一点会使您的代码不正确,尽管编译器没有义务检测它并提供诊断。