Vit*_*meo 27 c++ auto type-deduction c++14 decltype-auto
从我的个人经验以及从咨询答案到诸如decltype(auto)有什么用途的问题?我可以找到许多有价值的用例decltype(auto)
作为函数返回类型占位符。
但是,我在努力思考decltype(auto)
变量的任何有效(即有用,现实,有价值)用例时都非常费劲。我想到的唯一可能性是存储函数返回的结果以decltype(auto)
供以后传播,但auto&&
也可以在此使用,这样会更简单。
我什至搜索了我所有的项目和实验,其中391个出现的decltype(auto)
都是返回类型的占位符。
那么,变量是否有实际的用例decltype(auto)
?还是仅当用作返回类型占位符时此功能才有用?
您如何定义“现实”?
我正在寻找一个能提供价值的用例(即,不仅仅是显示功能如何工作的示例)decltype(auto)
,与诸如auto&&
或根本不声明变量的替代方案相比,哪里是最佳选择。
问题域无关紧要,它可能是一些晦涩的元编程极端案例或神秘的功能编程构造。但是,该示例需要使我接受“嘿,这很聪明/很漂亮!” 而使用任何其他功能来达到相同的效果将需要更多样板,或者存在某种缺陷。
L. *_* F. 17
本质上,变量的情况与函数相同。这个想法是我们用一个decltype(auto)
变量存储函数调用的结果:
decltype(auto) result = /* function invocation */;
Run Code Online (Sandbox Code Playgroud)
那result
是
非引用类型(如果结果是prvalue),
如果结果是左值,则为(可能是经过cv限定)左值引用类型,或者
如果结果是xvalue,则返回rvalue引用类型。
现在我们需要一个新版本的forward
来区分prvalue和xvalue :(forward
避免使用名称以避免ADL问题)
template <typename T>
T my_forward(std::remove_reference_t<T>& arg)
{
return std::forward<T>(arg);
}
Run Code Online (Sandbox Code Playgroud)
然后用
my_forward<decltype(result)>(result)
Run Code Online (Sandbox Code Playgroud)
不同于std::forward
,此函数用于转发decltype(auto)
变量。因此,它不会无条件返回引用类型,并且它应该与被称为decltype(variable)
,其可以是T
,T&
,或T&&
,以便它可以左值,xvalues,和prvalues之间进行区分。因此,如果result
是
非引用类型,则使用非引用调用第二次重载T
,并返回非引用类型,从而得出prvalue;
一个左值引用类型,然后使用调用第一个重载T&
并T&
返回,从而产生一个左值;
一个右值引用类型,然后使用调用第二个重载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);
}
Run Code Online (Sandbox Code Playgroud)
现在,如果调用表达式为
prvalue,result
则为非引用类型,函数返回非引用类型;
一个非常量左值,result
则为一个非常量左值引用,该函数返回一个非常量左值引用类型;
const左值,result
则为const左值引用,该函数返回const左值引用类型;
一个xvalue,则result
是一个rvalue引用类型,并且该函数返回一个rvalue引用类型。
赋予以下功能:
int f();
int& g();
const int& h();
int&& i();
Run Code Online (Sandbox Code Playgroud)
以下断言成立:
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&&>);
Run Code Online (Sandbox Code Playgroud)
如果auto&&
使用,则代码在区分prvalue和xvalue时会遇到一些麻烦。