请考虑以下事项:
auto list = std::make_tuple(1, 2, 3, 4);
/// Work like a charm
template <class T>
auto test1(T &&brush) -> decltype(std::get<0>( std::forward<T>(brush) )) {
return std::get<0>( std::forward<T>(brush) );
}
/// And now - C++14 feature
/// fail to compile - return value(temporary), instead of l-reference
template <class T>
auto test2(T &&brush) {
return std::get<0>( std::forward<T>(brush) );
}
int main()
{
auto &t1 = test1(list);
auto &t2 = test2(list);
}
http://coliru.stacked-crooked.com/a/816dea1a0ed3e9ee
两者,gcc和clang抛出错误:
main.cpp:26:11: error: non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'
auto &t2 = test2(list);
^ ~~~~~~~~~~~
它不应该像 decltype 一样工作吗?为什么不同?
已更新
如果std::get
与...相同,那不是吗? (我使用gcc 4.8)
template <class T>
auto&& test2(T &&brush) {
return std::get<0>( std::forward<T>(brush) );
}
答案 0 :(得分:7)
auto
只推导出对象类型,这意味着返回的对象的value-category不是返回类型的一部分。
使用auto
占位符,返回语句的类型由模板参数推导规则推导出来:
另一方面,
§ 7.1.6.4/7
auto specificer
[dcl.spec.auto]
如果占位符是auto type-speci fi er ,则使用模板参数推断规则确定推导出的类型。
decltype(auto)
使用扣除,就像decltype()
:
§ 7.1.6.4/7
auto specificer
[dcl.spec.auto]
如果占位符是
decltype(auto)
类型指定者,则声明的变量类型或函数的返回类型应仅为占位符。根据{{1}}中的描述确定为变量或返回类型推导出的类型,就像初始化程序是7.1.6.2
的操作数一样。
因此,对于完美转发返回类型,这是您应该使用的。这是它的外观:
decltype
因此,返回类型将是rvalue / lvaue-reference,具体取决于推导出的template <class T>
decltype(auto) test2(T &&brush) {
return std::get<0>(std::forward<T>(brush));
}
类型。
我在Coliru上测试了上面的内容,似乎brush
无法编译上面的代码,尽管使用clang++
它编译得很好。
答案 1 :(得分:2)
它不应该像decltype一样工作吗?为什么不同?
它应该像decltype
一样工作,但auto
在其他情况下与decltype
完全不同,并且他们不想制作auto
不一致。
相反,C ++ 1y为惯用推导函数返回类型引入了新语法decltype(auto)
。