struct STest : public boost::noncopyable {
STest(STest && test) : m_n( std::move(test.m_n) ) {}
explicit STest(int n) : m_n(n) {}
int m_n;
};
STest FuncUsingConst(int n) {
STest const a(n);
return a;
}
STest FuncWithoutConst(int n) {
STest a(n);
return a;
}
void Caller() {
// 1. compiles just fine and uses move ctor
STest s1( FuncWithoutConst(17) );
// 2. does not compile (cannot use move ctor, tries to use copy ctor)
STest s2( FuncUsingConst(17) );
}
上面的示例说明了在 C++11 中,正如在 Microsoft Visual C++ 2012 中实现的那样,函数的内部细节如何修改其返回类型。直到今天,我的理解是返回类型的声明是程序员需要知道的,以了解如何处理返回值,例如,当作为参数传递给后续函数调用时。不是这样。
我喜欢const
在适当的地方制作局部变量。它帮助我整理思路并清晰地构建算法。但请注意返回已声明的变量const
!即使不再访问该变量(return
毕竟执行了一条语句),并且即使声明的变量const
早已超出范围(参数表达式的评估已完成),它也无法移动,因此将被复制(如果无法复制,则编译失败)。
这个问题与另一个问题有关,移动语义和返回常量值。不同之处在于,在后者中,函数被声明为返回一个const
值。在我的示例中,FuncUsingConst
声明返回一个 volatile 临时变量。然而,函数体的实现细节会影响返回值的类型,并决定返回值是否可以用作其他函数的参数。
这种行为是否符合标准?
这怎么能算有用呢?
额外问题:考虑到调用和实现可能在不同的翻译单元中,编译器如何在编译时知道差异?
编辑:试图改写这个问题。
一个函数的结果怎么可能比声明的返回类型更多?函数声明不足以确定函数返回值的行为,这似乎完全可以接受吗?对我来说,这似乎是 FUBAR 的一个例子,我只是不确定是否应该责怪标准或微软的实施。
作为被调用函数的实现者,不能指望我知道所有的调用者,更不用说监控调用代码的每一个微小变化。另一方面,作为调用函数的实现者,我不能依赖被调用函数不返回一个恰好在函数实现范围内声明为 const 的变量。
函数声明是一个契约。现在值多少钱?我们在这里讨论的不是语义等价的编译器优化,比如复制省略,这很好,但不会改变代码的含义。无论是否调用了 copy ctor 都会改变代码的含义(甚至会破坏代码到无法编译的程度,如上图所示)。要理解我在这里讨论的尴尬,请考虑上面的“奖金问题”。