【问题标题】:Return type deduction with an explicit prototype in C++在 C++ 中使用显式原型进行返回类型推导
【发布时间】:2013-09-02 09:33:03
【问题描述】:

我一直在使用 -std=c++1y 的 g++ 支持的返回类型推导。
如果您使用显式返回类型对函数进行原型设计,然后尝试使用返回类型推导来定义该函数,编译器会抱怨一个模棱两可的旧声明:

std::string some_function();
...  
auto some_function(){ return std::string{"FOO"}; } //fails to compile

这不起作用有充分的理由吗?
我在定义中使用返回类型推导的理由是保持代码干净,但出于自我记录的原因,希望在原型中使用显式类型。关于何时以及何时不使用返回类型扣除的最佳实践建议将不胜感激:)

为了更清楚,我想回答:
1.这是编译器的实现错误吗? (我很确定不是)
2、这种扣款可以做,但提案标准不允许吗?如果是这样,为什么不呢?
3. 如果这真的是模棱两可的,有哪些例子可以推断出类型并尝试将其与显式前向声明相匹配会给您带来麻烦?
4. 这背后是否存在更深层次的具体实施问题?
5. 仅仅是疏忽吗?

【问题讨论】:

  • 何时使用,见my previous question
  • 我在proposalauto f(); // return type is unknown auto f() { return 42; } // return type is int auto f(); // redeclaration int f(); // error, declares a different function 中找到了这个。让我检查一下 N3690。
  • 啊,N3690和错误一样,不能用auto f()重载。我找不到它在哪里说的,但是您正在重载它而不是定义它。
  • 不是一个真正的答案,但我最好在声明和定义中以相同的方式拼写签名(确保它们保持不变),并在没有转发的情况下保持 auto声明。
  • @user1233963 是的,返回类型推导有效,但是如果您添加具有显式返回类型的前向声明,它会抱怨它是模棱两可的!这就是我的问题所在。

标签: c++ forward-declaration return-type c++14


【解决方案1】:

这是因为函数表和重载函数在 C++ 中的工作方式。

当编译器读取您的std::string some_function(); 时,它会创建一个点供它在二进制文件中引用,并说明“是否曾调用此函数跳转到该点”。

所以我们有一个看起来像这样的 vtable...

(Address offset)  (Symbol)
0x????????       std::string somefunction();

现在它会发送到您的auto some_function() {...}。通常它会首先在函数表中查看auto somefunction(); 是否存在于表中或其中的一些变体,但编译器注意到这是一个实现并且它具有 auto 关键字以便减少它写入*blank* some_function(); 的熵到函数表和关系来解决返回类型。

现在函数表看起来像这样......

(Address offset)  (Symbol)
0x????????       std::string somefunction();
0x????????       ????? somefunction();

因此,当它发现返回类型(在本例中为std::string)时,它会将代码编译成二进制文件。编译器现在知道返回类型是什么,因此它会转到函数表并更改 auto somefunction();std::string somefunction();

现在函数表看起来像这样......

(Address offset)  (Symbol)
0x????????       std::string somefunction();
0x????????       std::string somefunction();

现在编译器返回并继续编译函数。完成后,它会返回并完成 vtable 只是发现相同的符号在那里两次。现在我们指的是哪个符号也很模糊。

那么这是什么原因呢?

不是 100% 肯定,但 vtables 是在您的代码被处理到足以允许进行扣除类型之前很久就制作的。因此,编译器在那个阶段必须使用的唯一选择就是假设它是一个新符号。这只是我整天查看符号表并编写自己的 C++11 编译器时注意到的。

然而,我不能代表其他引入了大量优化和其他步骤的编译器,我只是简单地工作,但这是我对标准的理解。

类型是完全任意的。即使他们在扣除时不匹配也没关系。它永远不会那么远。问题来了,表中有两个相同的符号,不能重载返回类型。

【讨论】:

  • 如果我错了,并且除此之外的其他原因导致失败,我很想知道。它将帮助我在未来制作更好的编译器。
【解决方案2】:

你需要这样做:

auto some_function() -> decltype(std::string) { return std::string{"FOO"}; } 

更多信息请查看http://en.wikipedia.org/wiki/C%2B%2B11 -> 替代函数语法

【讨论】:

  • 这仅适用于 C++11,不适用于 C++1y,decltype 不应该存在。
  • c++1y 不是对 c++11 的更新,应该包含所有 c++11 的东西吗?
  • auto some_function() -> std::string 会很好,但这并不能解决我的问题,因为我想知道为什么返回类型推导不适用于显式类型的原型,而这会是一个显式类型的定义。
  • 是的(我想不出任何重大变化),但是说它必须以 C++11 的方式完成是错误的,因为有一种新的方式可以做到这一点。我可能误解了你的答案,而不是仅仅建议使用 C++11 语法来解决问题,但它仍然没有解释为什么这是必要的。
  • @mioiwakura:您的示例很简单,但是您可以将此函数的定义放在 .h 文件中。其他编译单元如何知道正确的返回类型是什么?我认为这是你不能这样做的方式,即使它看起来不错
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多