请考虑以下代码:
#include <initializer_list>
#include <vector>
auto cref_lambda = [] (const auto& il){
using T= typename decltype(il)::value_type;
};
auto cval_lambda = [] (const auto il){
using T=typename decltype(il)::value_type;
};
int main(){
std::initializer_list<int> il;
cref_lambda(il);
cval_lambda(il);
}
cref_lambda无法编译,因为我们正在尝试:: into一个引用。
我知道解决方法(使用std::remove_reference_t
或仅使用decltype(*il.begin());
),但我想知道是否有更好的习惯用法。
答案 0 :(得分:1)
解决手头问题的方法是将std::decay_t
添加到decltype
指令中。来自cppreference:
将lvalue-to-rvalue,array-to-pointer和function-to-pointer隐式转换应用于类型T,删除cv-qualifiers,并将结果类型定义为成员typedef类型。
最重要的是,它作为不符合上述任何注释的类型的标识。因此可以安全地编写
using T = typename std::decay_t<decltype(il)>::value_type;
获取不合格的value_type
,与函数签名无关。
现在问题的另一部分,如何写这个更短。好吧,在你的例子的情况下,可以说,因为你的lambda没有捕获任何东西,它也可以被自由函数模板替换。
template < typename T >
void cref(std::initializer_list<T> const &il) {
/* use T and il */
}
或者它是否适用于任何容器
template < typename U >
void cref(U const &il) {
using T = typename U::value_type;
/* use T and il */
}
第一种情况的明显优势是,您可以免费访问T = value_type
“。另一个优点(在我看来)是如果您不小心使用非std::initializer_list<T>
的内容调用此函数,您将获得更清晰的编译器错误。您可以通过添加static_assert
来弥补lambda的这个缺点,但这会使您最初想要找到的“短缺”更加紧张。
最后,如果你真的喜欢写作函数的lambda风格,或者你必须捕捉一些东西并且不能使用自由函数方法,你可能要考虑使用 GCC扩展来模板lambdas:< / p>
auto cref_lambda = [] <typename U> (U const &il){
using T = typename U::value_type;
};
这可能是你能得到的最短时间。