为什么这段C++代码在一些编译器中能够编译通过而在其他编译器中不能?

3

我在做作业的时候发现,我笔记本上的编译器比我们提交作业所用的机器上的编译器要宽容得多。 我的笔记本上的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 头文件,但我不明白为什么这段代码在我的笔记本电脑上居然编译通过了。这是怎么回事?


1
AppleClang的<iostream>头文件可能会间接包含std::tuple或其他std::tuple定义的源代码。你必须查看头文件才能确定。 - Kristopher Johnson
1
非可移植代码的问题是什么呢?嗯,你能猜到吗? - Kerrek SB
4个回答

5
不同的编译器有不同的头文件。C++头文件与您使用的编译器密切相关。可能的情况是,Clang的本身包含元组头文件,出于某种原因;因此,只需#include头文件,引用std::tuple的代码就可以轻松编译。当然,这将依赖于您的编译器的特定行为。不同的编译器有不同的头文件。C++标准不禁止一个头文件自动包含另一个头文件;但为了使用特定的类、模板或其他资源,确保这个类、模板或其他资源可供您的代码引用的唯一方法是显式地包含它的头文件。

4

不同的实现可能会选择将一些头文件包含在其他头文件中。您应该始终包含您使用的头文件。如果这样做,它将能够在两种编译器上编译。看起来clang在<iostream>中包含了<tuple>,而gcc没有。他们可以任意选择,因此您必须确保包含您需要的头文件。


1
这是另一种方式。 - Jonathan Wakely

3

标准头文件允许但不要求包含其他标准头文件。很可能clang的头文件直接或间接地包含。没有标准机制可以诊断由于这个原因你忘记了一个标准头文件。


1
代码能够被特定编译器编译通过并不意味着您的代码是正确的。正如在文档中所述,对于std::tuple,需要包含头文件<tuple>,违反这一要求会使您的代码不正确,尽管编译器没有义务检测并提供诊断信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接