为什么这个C ++代码与一些编译器编译而不是其他编译器?

时间:2017-02-16 21:33:07

标签: c++

我在做作业时注意到我的笔记本电脑上的编译器比我们预期用于提交的机器上的编译器更宽松。我的笔记本电脑上的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标题,但我不明白为什么这个代码在我的笔记本电脑上完全编译。这是怎么回事?

4 个答案:

答案 0 :(得分:5)

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

你可能拥有的是Clang的<iostream>本身#include的元组头文件,无论出于何种原因;因此,引用std::tuple的代码只会通过#include <iostream>标题快乐地编译。

当然,这将依赖于编译器的特定行为。

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

答案 1 :(得分:4)

不同的实现可能会选择在其他标头中包含一些标头。您应该始终包含您使用的标头。如果你这样做,那么它将与两个编译器一起编译。似乎clang在<tuple>中包含<iostream>,而gcc则不包含Application_BeginRequest。允许他们以任何方式执行此操作,您必须确保包含所需的标头。

答案 2 :(得分:3)

允许使用标准标头,但不要求包含其他标准标头。 clang的iostream标题可能直接或间接包含tuple。由于这个原因,没有标准的机制来诊断您忘记了标准标题。

答案 3 :(得分:1)

由特定编译器编译的代码不强制意味着您的代码是正确的。正如documentation中针对std::tuple所述,它需要包含标头<tuple>,违反此规定会使您的代码不正确,尽管编译器没有义务检测它并提供诊断。