考虑一个例子:
#include <iostream>
#include <type_traits>
#include <tuple>
int main() {
auto tup = std::make_tuple(1, 2);
auto [ a, b ] = tup;
decltype(auto) e = a;
std::cout << std::boolalpha << std::is_reference_v<decltype(e)> << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
在这个简单的例子中,clang(输出:)false和gcc(输出:)true不一致.记住,例如这个Q&As应该e是一个参考还是一个gcc bug?或者代码可能不正确?
昨天我在SO上看到了一个关于结构化绑定的有趣问题.
我们可以总结如下.请考虑以下示例代码:
#include <tuple>
#include <type_traits>
int main() {
auto tup = std::make_tuple(1, 2);
auto & [ a, b ] = tup;
// the following line won't compile for a isn't a reference
// static_assert(std::is_reference_v<decltype(a)>);
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下decltype(a)是int(可能),因为这种子弹(工作草案):
if
e是一个未加括号的id-expression,用于命名结构化绑定[...],decltype(e)是结构化绑定声明规范中给出的引用类型
这是@Curious在评论中为感兴趣的人提供的wandbox片段.它表明实际上a不是参考,仅此而已.
到目前为止好于原来的问题,OP问为什么它int,而不是int &和标准说,看上去像一个可以接受的答案.
无论如何,我想知道委员会为何如此决定.在一天结束时,a引用元组中的元素,我可以通过修改该元素a.换句话说,声明a看起来像一个引用,它的行为类似于引用,但它不是引用.
我可以忍受这个,但我想知道背后的原因是什么.为什么decltype(a)不能简单int &?亵渎者可以理解是否有一个有意义的理由?
如果在两种情况下都没有使用括号,那么函数(模板)的返回类型decltype(auto)和decltype(returning expression)返回类型之间有什么区别expr?
auto f() -> decltype(auto) { return expr; } // 1
auto f() -> decltype(expr) { return expr; } // 2
Run Code Online (Sandbox Code Playgroud)
上面f可以在任何上下文中定义/声明,可以是(成员)函数或(成员)函数模板,甚至是(泛型)lambda.expr可以依赖于任何模板参数.
在第二个版本中,两者expr都是完全相同的表达式,没有额外的括号.
在C++ 14及更高版本中使用第一种或第二种形式可以预期哪些差异?
如果括号到处使用怎么办?
请考虑C++模板中的引用:完整指南(第2版):
Run Code Online (Sandbox Code Playgroud)decltype(auto) ret{std::invoke(std::forward<Callable>(op), std::forward<Args>(args)...)}; ... return ret;需要注意的是,宣布
ret与auto&&不正确.作为引用,auto&&将返回值的生存期延长到其作用域的末尾,但不超出return对函数调用者的语句.
作者说这auto&&不适合完美转发回报值.但是,是否也没有decltype(auto)形成对xvalue/lvalue的引用?国际海事组织,decltype(auto)然后遭受同样的问题.那么,作者有什么意义呢?
编辑:
上面的代码片段应该放在这个函数模板中.
template<typename Callable, typename... Args>
decltype(auto) call(Callable&& op, Args&&... args) {
// here
}
Run Code Online (Sandbox Code Playgroud)