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

Is using explicit return type in one translation unit and deduced return type in another allowed?

我的问题与 this one 相似,但略有不同。

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

// exec.cpp

int foo();

int main() {
    return foo();
}

// lib.cpp

auto foo() {
    return 42;
}

编译和 link 它们一起合法吗?还是格式错误的 NDR?

注意:g++ 和 clang 都会使用命令 <compiler> exec.cpp lib.cpp -o program

生成预期的可执行文件(即 returns 42)

注意:可以说这是一种不好的做法(因为 return 类型可以在实现更改时更改,并破坏代码)。但是我还是很想知道答案。

以下所有标准参考均指N4861: March 2020 post-Prague working draft/C++20 DIS.


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

After all adjustments of types (during which typedefs are replaced by their definitions), the types specified by all declarations referring to a given variable or function shall be identical, except that declarations for an array object can specify array types that differ by the presence or absence of a major array bound ([dcl.array]). A violation of this rule on type identity does not require a diagnostic.

[dcl.spec.auto]/3 涵盖占位符类型可以与函数声明符一起出现,并且如果该声明符不包含 trailing-return-type (就像OP的例子一样)

[...] Otherwise [no trailing-return-type], the function declarator shall declare a function.

哪里

[...] the return type of the function is deduced from non-discarded return statements, if any, in the body of the function ([stmt.if]).

[dcl.fct]/1 涵盖不包含 trailing-return-type [emphasis mine 的函数声明符, 删除不适用于此特定示例的 opt 部分语法]:

In a declaration T D where D has the form [...] the type of the declarator-id in D isderived-declarator-type-list function of parameter-type-list returning T” [...]

因此,两个声明

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

两者都声明函数,其中 T D 声明中的 D 中关联的 declarator-id 的类型是

derived-declarator-type-list function of parameter-type-list returning T

在这两种情况下,Tint:

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

因此,声明 #1#2,在所有类型调整之后,具有相同的(函数)类型,从而满足 [basic.link]/11,以及 OP 的示例是良构的。然而,auto f() 定义的任何细微变化都可能导致推导的 return 类型不是 int,在这种情况下 [basic.link]/11 被违反, NDR.