c++98还是03?

引子

事情是这样的,有朋友看了我之前的文章(见此)后,提出了一个问题——

按文章中的说法:

最早,即上个世纪C++刚刚标准化时,make_pair的接口形式是:

1
2
3
template<class T1, class T2>

pair<T1, T2> make_pair(const T1 &x, const T2 &y);

参数类型是const &,这样可以避免不必要的拷贝。

然而,这样的定义存在问题。例如,make_pair("abc",3)这样的代码就会无法通过编译,因为T1类型会被推断成const char[4](而不是const char *),而pair<const char[4],int>是不合法的,因为first(T1)类型无法拷贝。

他为了验证这一说法,特意写了一段代码

1
2
3
4
5
6
7
8
9
#include <stdio.h>
#include <utility>

int main()
{
printf("%s\n",std::make_pair("abc",3).first);
return 0;
}
//g++ -std=c++98 -O0 -Wall -pedantic main.cpp && ./a.out

以上代码在指定 -std=c++98 选项的情况下,可以顺利通过编译,并未出现我文章中所说的问题。

按理说,这段代码应该要到 C++03 之后才能编译通过,可为什么在指定 -std=c++98 时依然没有问题呢?

-std=c++98到底意味着什么

我们先来看看 GCC 的官网是怎么说的:

The original ISO C++ standard was published as the ISO standard (ISO/IEC 14882:1998) and amended by a Technical Corrigenda published in 2003 (ISO/IEC 14882:2003). These standards are referred to as C++98 and C++03, respectively. GCC implements the majority of C++98 (export is a notable exception) and most of the changes in C++03. To select this standard in GCC, use one of the options -ansi, -std=c++98, or -std=c++03; to obtain all the diagnostics required by the standard, you should also specify -pedantic (or -pedantic-errors if you want them to be errors rather than warnings).

再看看 Clang 官网的说法:

Clang implements the following published and upcoming ISO C++ standards:

Language Standard Flag Available in Clang?
C++2c -std=c++2c Partial
C++23 -std=c++23 Partial
C++20 -std=c++20 Partial
C++17 -std=c++17 Clang 5
C++14 -std=c++14 Clang 3.4
C++11 -std=c++11 Clang 3.3
C++98 / C++03 -std=c++98 Yes (other than export)

从这两大主流编译器的文档可以看出,指定 -std=c++98,实际上编译器是按 C++03 的标准来编译代码的

如何真正复现 C++98 的行为?

在现代构建环境下,想要复现我上篇文章中提到的问题,是不太可行的。但如果使用 1998 年至 2003 年间流行的环境,比如微软的 VC6,就可以观察到这一现象。在 VC6 环境下,我那位朋友的代码会按预期出现编译错误:

Compiling…
test.cpp
c:\program files\microsoft visual studio\vc98\include\utility(21) : error C2536: ‘std::pair<char [4],int>::first’ : cannot specify explicit initializer for arrays
c:\program files\microsoft visual studio\vc98\include\utility(25) : see declaration of ‘first’
c:\program files\microsoft visual studio\vc98\include\utility(21) : while compiling class-template member function ‘__thiscall std::pair<char [4],int>::std::pair<char [4],int>(const char (&)[4],const int &)’
Error executing cl.exe.

当然,也可能有人会反驳:VC6 本身对 C++98 标准库的支持就不够好,这个验证并不严谨

这倒也简单,我们可以用当年的 STLport 替换 VC6 自带的标准库,使其符合当时的 C++98 规范。经过测试,结果依旧一致,代码仍然会在编译时报错。在此就不再赘述了。

03标准之于98标准的意义

与 1998 年的标准(ISO/IEC 14882:1998)相比,C++03(ISO/IEC 14882:2003)几乎没有引入新的特性,而是修正了 C++98 的一些缺陷。例如,之前文章提到的 pair 签名调整,以及 vector 中元素必须连续存储的规定等等。

对于开发者来说,C++03 不是一个“新标准”,而更像是 C++98 的终极形态,一个更加完善的 C++98。

正因如此,GCC、Clang 等编译器才会采取这种“挂羊头卖狗肉”的行为——你要求 C++98,我就给你 C++03

在专业领域,切勿望文生义

-std=c++98 并不意味着编译器会严格按照 1998 年的标准来编译 C++ 代码。这种“文意相左”的现象在其他领域也不少见,比如鲸鱼不是鱼,阿拉伯数字并非阿拉伯人发明,书记的工作并不是书写与记录,等等。

望文生义,在有些时候是不准确的。在自己的专业领域,更需要时刻提醒自己这一点。

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2024-2025 刘清
  • 访问人数: | 浏览次数: