是否允许在一个翻译单元中使用显式返回类型并在另一个翻译单元中使用推导返回类型?

Kae*_*Rin 14 c++ language-lawyer auto c++14

我的问题与类似,但略有不同。

假设我有两个翻译单元,exec.cpplib.cpp,如下:

// exec.cpp

int foo();

int main() {
    return foo();
}
Run Code Online (Sandbox Code Playgroud)

// lib.cpp

auto foo() {
    return 42;
}
Run Code Online (Sandbox Code Playgroud)

将它们编译和链接在一起是否合法?还是格式错误的 NDR?

注意:g++ 和 clang 都使用命令生成预期的可执行文件(即返回 42) <compiler> exec.cpp lib.cpp -o program

注意:可以说这是一个不好的做法(因为如果实现发生变化,返回类型可能会改变,并破坏代码)。但我还是想知道答案。

dfr*_*fri 6

以下所有标准参考均指N4861:2020 年 3 月后布拉格工作草案/C++20 DIS。.


来自[basic.link]/11 [强调我的]:

在所有类型调整后(在此期间,typedef 被它们的定义替换),所有引用给定变量或函数的声明指定的类型应该是相同的,除了数组对象的声明可以指定不同的数组类型缺少主数组绑定([dcl.array])。在类型标识上违反此规则不需要诊断。

[dcl.spec.auto]/3涵盖了占位符类型可以与函数声明符一起出现,并且如果此声明符不包含尾随返回类型(就像 OP 的示例一样)

[...] 否则 [无尾随返回类型],函数声明器应声明一个函数

在哪里

[...] 函数的返回类型是从函数return体 ([stmt.if]) 中的非丢弃语句(如果有)推导出来的。

[dcl.fct]/1涵盖了不包含尾随返回类型的函数声明[强调我的,删除在此特定示例中不适用的语法的opt部分]:

在声明T D,其中D的形式为[...]的类型说明符-IDD衍生的说明符类型列表的功能参数类型列表返回T” [...]

因此,两个声明

int f();      // #1
auto foo() {  // #2
    // [dcl.spec.auto]/3:
    // return type deduced to 'int'
}
Run Code Online (Sandbox Code Playgroud)

两个声明函数,其中相关联的类型说明符-IDD这些的T D声明是

“返回参数类型列表的派生声明符类型列表函数”T

在这两种情况下,Tint

  • 中明确指定#1
  • 根据 [dcl.spec.auto]/3 in 推断#2

因此,声明#1#2,经过所有类型的调整,具有相同的(函数)类型,从而满足 [basic.link]/11,并且 OP 的示例格式良好。auto f()然而,对 的定义的任何轻微变化都可能导致推导出的返回类型不是int,在这种情况下,[basic.link]/11 被违反,NDR。