我一直在玩g ++支持的返回类型演绎,-std = c ++ 1y 如果您使用显式返回类型对函数进行原型化,然后尝试使用返回类型推导来定义函数,则编译器会抱怨一个模糊的旧声明:
std::string some_function();
...
auto some_function(){ return std::string{"FOO"}; } //fails to compile
为什么这不起作用有充分的理由吗? 我在定义中使用返回类型推导的基本原理是保持代码干净,但是为了自我记录的原因需要原型中的显式类型。关于何时以及何时不使用退货类型扣除的最佳做法的建议将不胜感激:)
为了更清楚,我想答复:
1.这是编译器中的实现错误吗? (我很确定不是)
2.这种类型的扣除是否可以完成,但标准的提案不允许这样做?如果是这样,为什么不呢?
3.如果这真的很模糊,那么推断类型并尝试将其与明确的前向声明相匹配的一些例子会让你遇到麻烦?
4.这背后是否有更深层次的具体实施问题?
这只是一种疏忽吗?
答案 0 :(得分:6)
这是因为函数表和重载函数在C ++中的工作方式。
当编译器读取你的std::string some_function();
时,它会在二进制文件中创建一个引用它的位置,并说“是否”这个函数被调用跳转到这个位置“。
所以我们有一个看起来像这样的vtable ......
(Address offset) (Symbol)
0x???????? std::string somefunction();
现在它到达了auto some_function() {...}
。通常它首先会在函数表中查看表中是否存在auto somefunction();
或其中的某些变体,但编译器注意到这是一个实现,并且它具有auto关键字,以减少它写入的熵{ {1}}到函数表和绑定来解决返回类型。
现在,Function表看起来像这样......
*blank* some_function();
因此,当它找到返回类型(在这种情况下为(Address offset) (Symbol)
0x???????? std::string somefunction();
0x???????? ????? somefunction();
)时,它会将代码编译成二进制文件。编译器现在知道返回类型是什么,因此它转到函数表并更改std::string
auto somefunction();
。
现在,Function表看起来像这样......
std::string somefunction();
现在编译器返回并继续编译该函数。一旦完成,它就会返回并完成vtable,只发现两次相同的符号。现在我们指的是哪个符号也很模糊。
那么这是什么原因?
不是100%肯定,但是在你的代码被足够努力以允许进行演绎类型之前很久就会制作vtable。因此,编译器必须在该阶段使用的唯一选择是假设它是一个新符号。这只是我注意到整天看着符号表并编写自己的C ++ 11编译器的东西。
但是,对于其他引入了大量优化和其他步骤的编译器,我无法说话,我只是简单地使用,但这是我对标准的理解。
最后一种类型是完全随意的。如果它们在扣除时不匹配则无关紧要。它永远不会那么遥远。问题出现在表中有两个相同的符号,并且您不能在返回类型上重载。
答案 1 :(得分:-3)
你需要这样做:
auto some_function() -> decltype(std::string) { return std::string{"FOO"}; }
了解详情http://en.wikipedia.org/wiki/C%2B%2B11 - >替代函数语法