无论是从我的个人经验还是从咨询问题的答案来看,诸如decltype(auto(有哪些用途?我可以找到很多有价值的用例,decltype(auto)
作为函数返回类型占位符。
但是,我正在努力思考decltype(auto)
变量的任何有效(即有用,现实,有价值的(用例。想到的唯一可能性是存储函数返回decltype(auto)
的结果以供以后传播,但auto&&
也可以在那里使用,而且会更简单。
我甚至搜索了我所有的项目和实验,decltype(auto)
出现的 391 次都是返回类型的占位符。
那么,decltype(auto)
变量是否有任何现实的用例?或者此功能仅在用作返回类型占位符时才有用?
你如何定义"现实"?
我正在寻找一个提供价值的用例(即它不仅仅是一个展示该功能如何工作的示例(,与auto&&
或根本不声明变量等替代方案相比,decltype(auto)
是完美的选择。
问题域并不重要,它可能是一些晦涩的元编程极端情况或晦涩的函数式编程结构。但是,这个例子需要让我去"嘿,这很聪明/很漂亮!">并且使用任何其他功能来实现相同的效果需要更多的样板或有某种缺点。
本质上,变量的情况对于函数是相同的。 这个想法是,我们将函数调用的结果与decltype(auto)
变量一起存储:
decltype(auto) result = /* function invocation */;
然后,result
是
如果结果是 PR值,则为非引用类型,
(可能符合 CV 条件的(左值引用类型(如果结果是左值(,或
如果结果为 x值,则为 rvalue 引用类型。
现在我们需要一个新的forward
版本来区分 prvalue 情况和 xvalue 情况:(避免使用名称forward
以防止 ADL 问题(
template <typename T>
T my_forward(std::remove_reference_t<T>& arg)
{
return std::forward<T>(arg);
}
然后使用
my_forward<decltype(result)>(result)
与std::forward
不同,此函数用于转发decltype(auto)
变量。 因此,它不会无条件地返回引用类型,它应该使用decltype(variable)
调用,它可以是T
、T&
或T&&
,以便它可以区分左值、x值和 pr值。 因此,如果result
类型,然后使用非引用
T
调用第二个重载,并返回非引用类型,从而生成 PR值;一个左值引用类型,然后用
T&
调用第一个重载,并返回T&
,从而得到一个左值;一个 rvalue 引用类型,然后使用
T&&
调用第二个重载,并返回T&&
,从而生成 xValue。
下面是一个示例。 考虑您要包装std::invoke
并将某些内容打印到日志中:(该示例仅用于说明(
template <typename F, typename... Args>
decltype(auto) my_invoke(F&& f, Args&&... args)
{
decltype(auto) result = std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
my_log("invoke", result); // for illustration only
return my_forward<decltype(result)>(result);
}
现在,如果调用表达式是
一个 prvalue,则
result
是非引用类型,该函数返回非引用类型;一个非常量左值,则
result
是非常量左值引用,该函数返回非常量左值引用类型;一个常量左值,则
result
是常量左值引用,该函数返回常量左值引用类型;一个 xValue,然后
result
是 rvalue 引用类型,该函数返回 rvalue 引用类型。
给定以下功能:
int f();
int& g();
const int& h();
int&& i();
以下断言成立:
static_assert(std::is_same_v<decltype(my_invoke(f)), int>);
static_assert(std::is_same_v<decltype(my_invoke(g)), int&>);
static_assert(std::is_same_v<decltype(my_invoke(h)), const int&>);
static_assert(std::is_same_v<decltype(my_invoke(i)), int&&>);
(现场演示,仅移动测试用例(
如果改用auto&&
,代码在区分 prvalues 和 xvalues 时会遇到一些麻烦。
可能不是一个非常深刻的答案,但基本上decltype(auto)
被提议用于返回类型推导,以便能够在返回类型实际上是引用时推断引用(与永远不会推断引用的普通auto
相反,或者auto&&
总是这样做(。
它也可以用于变量声明的事实并不一定意味着应该有比其他方案更好的情况。事实上,在变量声明中使用decltype(auto)
只会使代码读取复杂化,因为对于变量声明,is具有完全相同的含义。另一方面,auto&&
窗体允许您声明一个常量变量,而decltype(auto)
则不允许。