不仅没有这样的功能,永远不可能有。这样做会使定义良好的程序格式错误或最糟糕,具有未定义的行为。
考虑这个简单的格式良好的程序:
struct X {};
auto bar(X x) -> decltype(x)
{
return x;
}
auto test()
{
bar(X{});
}
你会如何改造它?没有办法让bar引用而不改变程序的语义或使其成为UB
如果你让bar 取左值引用,那么它就不能接受一个临时的:
struct X {};
auto bar(X& x) -> decltype(x)
{
return x;
}
auto test()
{
bar(X{});
}
<source>:12:5: error: no matching function for call to 'bar'
bar(X{});
^~~
<source>:4:6: note: candidate function not viable: expects an l-value for 1st argument
auto bar(X& x) -> decltype(x)
^
1 error generated.
如果你让它接受一个右值引用,那么你不能在没有进一步修改的情况下返回它:
struct X {};
auto bar(X&& x) -> decltype(x)
{
return x;
}
auto test()
{
bar(X{});
}
<source>:6:12: error: rvalue reference to type 'X' cannot bind to lvalue of type 'X'
return x;
^
1 error generated.
好的,您可以通过移动参数来解决这个特殊问题。但这远远超出了您最初设定的更改范围。尽管如此,为了论证,假设您这样做了,或者原始程序已经这样做了:
#include <utility>
struct X { };
auto bar(X&& x) -> decltype(x)
{
return std::move(x);
}
auto test()
{
bar(X{});
}
这最终确实编译了。但是你看到问题了吗?你返回一个过期对象的引用,你返回一个悬空引用:
// before
#include <utility>
struct X { auto foo() const {} };
auto bar(X x) -> decltype(x) // bar returns a prvalue
{
return x;
// or
// return std::move(x); // redundant, but valid and equivalent
}
auto test()
{
const X& xr = bar(X{}); // xr prolongs the lifetime of the temporary returned by `bar`
xr.foo(); // OK, no problem
}
// after
#include <utility>
struct X { auto foo() const {} };
auto bar(X&& x) -> decltype(x) // now bar returns an xvalue
{
return std::move(x);
}
auto test()
{
const X& xr = bar(X{}); // xr cannot prolong the life of an xvalue
// the temporary objects created as part of calling `bar` is now expired
// and xr references it
// any attempt to use xr results in UB
xr.foo(); // Undefined Behaviour
}
没有办法做你想做的事。
程序员的负担在你身上:如果你需要值就写值,如果你需要引用就写引用。就这么简单。