考虑一个例子:
#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?或者代码可能不正确?
强制复制省略是否适用于通过结构化绑定进行分解?以下哪种情况适用于?
// one
auto [one, two] = std::array<SomeClass>{SomeClass{1}, SomeClass{2}};
// two
auto [one, two] = std::make_tuple(SomeClass{1}, SomeClass{2});
// three
struct Something { SomeClass one, two; };
auto [one, two] = Something{};
Run Code Online (Sandbox Code Playgroud)
我怀疑只有第三种情况允许复制省略,因为前两个会被"分解"通过std::get<>
并std::tuple_size<>
和std::get<>
当参数是右值返回xvalues
标准的引用也很好!
在std :: unordered_map上运行基于范围的for循环时,似乎循环变量的类型不使用引用类型:
std::unordered_map<int, int> map = { {0, 1}, {1, 2}, {2, 3} };
for(auto&[l, r] : map)
static_assert(std::is_same_v<decltype(r), int&>);
Run Code Online (Sandbox Code Playgroud)
MSVC 2017,gcc 8.2和clang 7.0.0都报告了一个失败的断言.将此反对到std :: vector,其中断言不会失败,正如人们所期望的那样:
std::vector<int> vec = { 1, 2, 3 };
for(auto& r : vec)
static_assert(std::is_same_v<decltype(r), int&>);
Run Code Online (Sandbox Code Playgroud)
然而,在MSVC 2017和gcc 8.2上,修改局部变量r的循环将具有可观察到的副作用:
#include <iostream>
#include <type_traits>
#include <unordered_map>
#include <vector>
int main() {
std::unordered_map<int, int> a = { {0, 1}, {1, 2}, {2, 3} };
for(auto[l, r] : a)
std::cout << l << "; " << …
Run Code Online (Sandbox Code Playgroud) 如果我正确理解了这个答案并引用了标准部分[dcl.type.auto.deduct-5],那么代码如下:
decltype(auto) a = e;
Run Code Online (Sandbox Code Playgroud)
总是相当于
decltype( e ) a = e;
Run Code Online (Sandbox Code Playgroud)
但是现在问题出现了,而不是e
我把lambda表达式放到decltype(auto)
:
decltype(auto) lambda = [](){};
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是,这在gcc和clang中成功编译.我所经历的冲击的原因在于标准,其中特别指出lambda不应出现在未评估的操作数中[expr.prim.lambda#2](强调我的):
lambda-expression是一个prvalue,其结果对象称为闭包对象.lambda表达式不应出现在未评估的操作数,模板参数,别名声明,typedef声明或函数体和默认参数之外的函数或函数模板的声明中.
但正如我所提到的,这个例子相当于:
decltype([](){}) lambda = [](){};
Run Code Online (Sandbox Code Playgroud)
明确写出的上述代码显然是不正确的.当然,我们可以假设[](){}
里面的语句decltype
是一种引用,实际上并不是像结构化绑定那样的引用,但是标准中有一条特殊的规则,我错过了覆盖lambda的初始化decltype(auto)
?
据我所知,C++ 17中结构化绑定引入的标识符实际上是对某些"隐藏"变量的引用.这样
auto [ a, b ] = std::make_tuple(1, 2);
Run Code Online (Sandbox Code Playgroud)
是一种等同于
auto e = std::make_tuple(1, 2);
auto& a = std::get<0>(e);
auto& b = std::get<1>(e);
Run Code Online (Sandbox Code Playgroud)
但是,如果我打印出来std::is_reference<decltype(a)>::value
,我会0
在1
第二种情况下进入第一种情况.这是为什么?
#include <type_traits>
int main()
{
int arr[1] = { 6 };
auto& ref1 = arr[0];
static_assert( std::is_same_v<decltype( ref1 ), int&> ); //ok
auto& [ ref2 ] = arr;
static_assert( std::is_same_v<decltype( ref2 ), int> ); //ok
static_assert( std::is_same_v<decltype( ref2 ), int&> ); //error
}
Run Code Online (Sandbox Code Playgroud)
标识符ref1
与ref2
该示例之间的重要区别是什么?据我所知,ref2
在结构绑定中也有一个引用类型,但为什么要为它decltype
指示一个非引用类型?
在[dcl.struct.bind] 9.6.4中,当初始化器是正确定义的类类型时,有结构化绑定的定义std\xe2\x80\x8b::\xe2\x80\x8btuple_\xc2\xadsize<E>\xe2\x80\x8b::\xe2\x80\x8bvalue
:
\n\n...变量以唯一名称ri引入,如下所示:
\n
\n S Ui ri = 初始值设定项 ;
\n每个vi都是Ti类型的左值的名称,该左值引用绑定到ri的对象;\n引用的类型是Ti。
我的问题是为什么需要引入ri,我们不能直接定义标识符vi作为对结果的引用吗get<i>(e)
?